diff --git a/CMake/BuildConfigurations/All.cmake b/CMake/BuildConfigurations/All.cmake
index 6a3b24125e..2e65fd8460 100644
--- a/CMake/BuildConfigurations/All.cmake
+++ b/CMake/BuildConfigurations/All.cmake
@@ -1,45 +1,44 @@
set(MITK_CONFIG_PACKAGES )
set(_apple_package_excludes)
set(_package_excludes
${_apple_package_excludes}
OpenCL
OpenMP
SYSTEM_Boost
Boost_LIBRARIES
SYSTEM_PYTHON
SUPERBUILD
POLHEMUS_TRACKER
MICROBIRD_TRACKER
MICROBIRD_TRACKER_INCLUDE_DIR
MICROBIRD_TRACKER_LIB
MICRON_TRACKER
OPTITRACK_TRACKER
SPACENAVIGATOR
TOF_KINECT
TOF_KINECTV2
TOF_MESASR4000
TOF_PMDCAMBOARD
TOF_PMDCAMCUBE
TOF_PMDO3
US_TELEMED_SDK
videoInput
- WIIMOTE
)
get_cmake_property(_cache_vars CACHE_VARIABLES)
foreach(_cache_var ${_cache_vars})
string(REGEX REPLACE "MITK_USE_(.+)" "\\1" _package "${_cache_var}")
if(_package AND NOT _package STREQUAL _cache_var)
list(FIND _package_excludes ${_package} _index)
if(_index EQUAL -1)
list(APPEND MITK_CONFIG_PACKAGES ${_package})
endif()
endif()
endforeach()
set(MITK_BUILD_ALL_APPS ON CACHE BOOL "Build all MITK applications" FORCE)
set(MITK_BUILD_ALL_PLUGINS ON CACHE BOOL "Build all MITK plugins" FORCE)
set(MITK_BUILD_EXAMPLES ON CACHE BOOL "Build the MITK examples" FORCE)
set(BLUEBERRY_BUILD_ALL_PLUGINS ON CACHE BOOL "Build all BlueBerry plugins" FORCE)
diff --git a/CMake/Whitelists/FlowBenchSegmentation.cmake b/CMake/Whitelists/FlowBenchSegmentation.cmake
index 60c1587601..c0eedb2dfb 100644
--- a/CMake/Whitelists/FlowBenchSegmentation.cmake
+++ b/CMake/Whitelists/FlowBenchSegmentation.cmake
@@ -1,55 +1,54 @@
set(enabled_modules
Core
CppMicroServices
DICOM
DICOMPM
DataTypesExt
AlgorithmsExt
DICOMQI
Multilabel
SceneSerializationBase
DICOMPMIO
DICOMImageIO
ContourModel
DICOMSegIO
LegacyGL
MapperExt
SceneSerialization
LegacyIO
IOExt
MultilabelIO
AppUtil
QtWidgets
QtWidgetsExt
Segmentation
SegmentationUI
PlanarFigure
Annotation
SurfaceInterpolation
GraphAlgorithms
ImageExtraction
ImageStatistics
)
set(enabled_plugins
org.blueberry.core.commands
org.blueberry.core.expressions
org.blueberry.core.runtime
org.blueberry.ui.qt
org.blueberry.ui.qt.help
org.blueberry.ui.qt.log
-org.mitk.core.ext
org.mitk.core.services
org.mitk.gui.common
org.mitk.gui.qt.application
org.mitk.gui.qt.common
org.mitk.gui.qt.datamanager
org.mitk.gui.qt.ext
org.mitk.gui.qt.flow.segmentation
org.mitk.gui.qt.flowapplication
org.mitk.gui.qt.imagenavigator
org.mitk.gui.qt.properties
org.mitk.gui.qt.segmentation
org.mitk.gui.qt.stdmultiwidgeteditor
org.mitk.planarfigure
)
diff --git a/CMake/manifest.xml.in b/CMake/manifest.xml.in
index 1c020827f9..09d3679994 100644
--- a/CMake/manifest.xml.in
+++ b/CMake/manifest.xml.in
@@ -1,10 +1,10 @@
UTF-8
- PerMonitorV2
+ PerMonitorV2
diff --git a/Documentation/Doxygen/3-DeveloperManual/Application/DevelopmentApplication.dox b/Documentation/Doxygen/3-DeveloperManual/Application/DevelopmentApplication.dox
index baf97ed86f..587d9c2803 100644
--- a/Documentation/Doxygen/3-DeveloperManual/Application/DevelopmentApplication.dox
+++ b/Documentation/Doxygen/3-DeveloperManual/Application/DevelopmentApplication.dox
@@ -1,27 +1,22 @@
/**
\page DevelopmentApplication Developing with the MITK Application Framework
MITK offers a powerful application featuring a plugin system and many
predefined plugins. You can configure this application to offer a set of
functionality to the user and easily create an installer.
Working with the application, you will have to learn about extension
points and the Blueberry framework itself. If you are new to the matter,
please also consult \ref Architecture and \ref FirstSteps.
- \subpage BlueBerryIntro
- \subpage BlueBerryExamples
The BlueBerry framework extension-point reference is available here:
- \subpage BlueBerryExtPointsIndex
-
-The MITK application extension-point reference is available here:
-
- - \subpage mitkExtPointsIndex
-
*/
diff --git a/Documentation/Doxygen/3-DeveloperManual/Application/ExtensionPointReference.dox b/Documentation/Doxygen/3-DeveloperManual/Application/ExtensionPointReference.dox
deleted file mode 100644
index e324ea7885..0000000000
--- a/Documentation/Doxygen/3-DeveloperManual/Application/ExtensionPointReference.dox
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
-
-\page mitkExtPointsIndex MITK Extension-Point Reference
-
-- \subpage mitkExtPointsIndex_InputDevices
-
-\page mitkExtPointsIndex_InputDevices Input Devices
-
-\tableofcontents
-
-\section mitkExtPointsIndex_InputDevices_Identifier Identifier
-
-\c org.mitk.core.ext.inputdevices
-
-\section mitkExtPointsIndex_InputDevices_Description Description
-
-This extension point is used to define additional input devices.
-
-\section mitkExtPointsIndex_InputDevices_ConfigurationMarkup Configuration Markup
-
-\code{.unparsed}
-
-
-\endcode
-
-- point: a fully qualified identifier of the target extension point
-- id: an optional identifier of the extension instance
-- name: an optional name of the extension instance
-
-\code{.unparsed}
-
-
-\endcode
-
-- id: the identifier of the input device
-- name: an optional name of the input device
-- class: a fully qualified name of the class that implements mitk::IInputDevice.
-
-\code{.unparsed}
-
-\endcode
-
-An optional subelement whose body should contain text providing a short description of the input device.
-
-\section mitkExtPointsIndex_InputDevices_Examples Examples
-
-\code{.unparsed}
-
-
- My new 20-dimensional input device
-
-
-\endcode
-
-*/
diff --git a/Documentation/Doxygen/3-DeveloperManual/DeveloperManualPortal.dox b/Documentation/Doxygen/3-DeveloperManual/DeveloperManualPortal.dox
index 678ce379c8..8ab74c6556 100644
--- a/Documentation/Doxygen/3-DeveloperManual/DeveloperManualPortal.dox
+++ b/Documentation/Doxygen/3-DeveloperManual/DeveloperManualPortal.dox
@@ -1,31 +1,28 @@
/**
\developersguidemainpage{DeveloperManualPortal} Developer Manual
Development with MITK can happen under several conditions. Depending on whether you are using the Toolkit or the entire application, different sections may apply to you.
In case you are unsure about what you need, please refer to \link Architecture The Architecture of MITK text\endlink.
An extensive Introduction to MITK is available under \link StartingDevelopment Starting your MITK Development\endlink.
Once you have made yourself familiar with MITK, you should have a look at the \link Concepts Development Concepts\endlink, as MITK implements a lot of high-level functionality.
Knowing about these concepts will prevent you from reimplementing functionality.
Once you start consuming more specific functionality, the \link MITKModuleManualsListPage Module Manual\endlink will be helpful to understand how a specific plugin works and what functionality it provides.
- \subpage StartingDevelopment
- \ref Architecture
- \ref SettingUpMITK
- \ref GettingToKnowMITK
- \ref FirstSteps
- \ref AboutTestingPage
- \subpage Concepts
- \subpage MITKModuleManualsListPage
- \subpage DevelopmentApplication
-
- - \ref mitkExtPointsIndex
-
- \subpage DeploymentPage
*/
diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/GettingToKnow/CMakeFAQ.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/GettingToKnow/CMakeFAQ.dox
index eb1e126554..475dd319e3 100644
--- a/Documentation/Doxygen/3-DeveloperManual/Starting/GettingToKnow/CMakeFAQ.dox
+++ b/Documentation/Doxygen/3-DeveloperManual/Starting/GettingToKnow/CMakeFAQ.dox
@@ -1,44 +1,44 @@
/**
\page CMAKE_FAQ CMake FAQ
\section CMAKE_FAQ_General A general comment
MITK uses %CMake for configuration. If you want to develop either using MITK as a toolkit or by extending the capabilities of the applications provided by us, we recommend using %CMake for your own project too.
While it might be possible to use MITK in conjunction with other options, such as QMake or setting up your own project manually it will invariably involve a lot of work and probably hacks as well.
As we do have no experience with this, we will not be able to help you.
Be prepared to do a lot of tweaking on by yourself.
This guide does not try to give a general introduction to CMake, instead it tries to answer some basic questions that might arise for those new to %CMake, to help you get started on MITK. For a more comprehensive introduction on %CMake see here.
We will assume in this guide, that the path to your source is /MITK/.
\section CMAKE_FAQ_Question Basic Questions
\subsection CMAKE_FAQ_Question_WhereGetIt Where do I get CMake and what version do I need?
See \ref BuildInstructions_Prerequisites.
\subsection CMAKE_FAQ_Question_NewPluginNothing I coded a new plugin for the Workbench and nothing happened. Why?
Do note that you need to move the source to the Plugins directory and you will have to add the plugin to the config file (most likely Plugins/PluginList.cmake). After that see \ref CMAKE_FAQ_Question_HowDoIActivatePlugin.
\subsection CMAKE_FAQ_Question_HowDoIActivatePlugin I want to use a plugin, how do I activate it?
- Start %CMake in the `MITK-build` directory inside your superbuild folder. E.g.
`cd ~//MITK-build`
`ccmake .` or `cmake-gui .`
- Optional: *Configure* to see all %CMake variables.
- Find the variable `MITK_BUILD_` and activate it. The `` refers to the package name of the plugin.
- E.g. the plugin-id (also, the package name) `org.mitk.core.ext` is the sub-directory of same name in plugins directory (`~/MITK/Plugins/`).
+ E.g. the plugin-id (also, the package name) `org.mitk.gui.qt.application` is the sub-directory of same name in plugins directory (`~/MITK/Plugins/`).
- *Configure*, again
- *Generate*
- Rebuild the `MITK-build` target using your development environment.
\subsection CMAKE_FAQ_Question_HowDoIActivateModule I want to use a module, how do I activate it?
Modules are build automatically if a plugin that requires them is activated. See \ref CMAKE_FAQ_Question_HowDoIActivatePlugin.
\subsection CMAKE_FAQ_Question_HowOwnToolkits MITK always downloads the toolkits, but I want to use my own.
This is covered in \ref HowToNewProjectCustomizingMITKConfigure.
\subsection CMAKE_FAQ_Question_HowOwnProjectMITK I want to use an MITK plugin in my own project but I can not find it.
See \ref HowToNewProjectAddingMITKFunctionality.
*/
diff --git a/Examples/Plugins/org.mitk.example.gui.customviewer/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.customviewer/manifest_headers.cmake
index 058dcf0b91..170a057a2d 100644
--- a/Examples/Plugins/org.mitk.example.gui.customviewer/manifest_headers.cmake
+++ b/Examples/Plugins/org.mitk.example.gui.customviewer/manifest_headers.cmake
@@ -1,9 +1,8 @@
set(Plugin-Name "MITK Example Custom Viewer")
set(Plugin-Version "1.0.0")
set(Plugin-Vendor "German Cancer Research Center (DKFZ)")
set(Plugin-ContactAddress "https://www.mitk.org")
set(Require-Plugin
- org.mitk.core.ext # Registers file reader factories
org.mitk.gui.qt.application # Initializes GlobalInteraction and registers MITK Core factories
)
diff --git a/Modules/Classification/CLVigraRandomForest/test/files.cmake b/Modules/Classification/CLVigraRandomForest/test/files.cmake
index 3f04b16d08..9a4351245d 100644
--- a/Modules/Classification/CLVigraRandomForest/test/files.cmake
+++ b/Modules/Classification/CLVigraRandomForest/test/files.cmake
@@ -1,3 +1,5 @@
-set(MODULE_TESTS
- mitkVigraRandomForestTest.cpp
-)
+set(MODULE_TESTS "")
+
+if(NOT APPLE)
+ list(APPEND MODULE_TESTS mitkVigraRandomForestTest.cpp)
+endif()
diff --git a/Modules/Core/include/mitkInteractionConst.h b/Modules/Core/include/mitkInteractionConst.h
index e83f33b429..0df91c3715 100644
--- a/Modules/Core/include/mitkInteractionConst.h
+++ b/Modules/Core/include/mitkInteractionConst.h
@@ -1,776 +1,762 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef mitkInteractionConst_h
#define mitkInteractionConst_h
//##Documentation
//## @file mitkInteractionConst.h
//## @brief Constants for most interaction classes, due to the generic StateMachines.
//##
//## Changes in Type, ButtonState or Key has to be don in mitkEventMapper.cpp, too.
//## @ingroup Interaction
/*Prefixes for Constants:
E = Enumeration
EID = EventId's
Op = Operations
Ac = Action
Type_ = Type of Event
BS_ = ButtonStates and Buttons
Key_ = Keys like in QT
*/
namespace mitk
{
// Constants for EventIds; use the according constant to through an event in the code
enum EEventIds
{
EIDNULLEVENT = 0,
EIDLEFTMOUSEBTN = 1,
EIDRIGHTMOUSEBTN = 2,
EIDLEFTMOUSEBTNANDSHIFT = 3,
EIDMIDDLEMOUSEBTN = 4,
EIDLEFTMOUSEBTNANDCTRL = 5,
EIDMIDDLEMOUSEBTNANDCTRL = 6,
EIDRIGHTMOUSEBTNANDCTRL = 7,
EIDLEFTMOUSEBTNDOUBLECLICK = 8,
EIDMOUSEWHEEL = 9,
EIDLEFTMOUSERELEASE = 505,
EIDMIDDLEMOUSERELEASE = 506,
EIDRIGHTMOUSERELEASE = 507,
EIDLEFTMOUSERELEASEANDSHIFT = 508,
EIDMOUSEMOVE = 520,
EIDLEFTMOUSEBTNANDMOUSEWHEEL = 521,
EIDRIGHTMOUSEBTNANDMOUSEWHEEL = 522,
EIDMIDDLEMOUSEBTNANDMOUSEWHEEL = 523,
EIDLEFTMOUSEBTNANDMOUSEMOVE = 530,
EIDRIGHTMOUSEBTNANDMOUSEMOVE = 531,
EIDMIDDLEMOUSEBTNANDMOUSEMOVE = 533,
EIDCTRLANDLEFTMOUSEBTNANDMOUSEMOVE = 534,
EIDCTRLANDRIGHTMOUSEBTNANDMOUSEMOVE = 535,
EIDCTRLANDMIDDLEMOUSEBTNANDMOUSEMOVE = 536,
EIDCTRLANDLEFTMOUSEBTNRELEASE = 537,
EIDCTRLANDRIGHTMOUSEBTNRELEASE = 538,
EIDCTRLANDMIDDLEMOUSEBTNRELEASE = 539,
EIDSHIFTANDCTRLANDMIDDLEMOUSEBTN = 540,
EIDSHIFTANDLEFTMOUSEBTNANDMOUSEMOVE = 541,
EIDSHIFTANDCTRLANDMOUSEMOVE = 542,
EIDSHIFTANDCTRLANDMOUSERELEASE = 543,
EIDALTANDLEFTMOUSEBTN = 600,
EIDALTANDLEFTMOUSEBTNANDMOUSEMOVE = 610,
EIDALTANDLEFTMOUSERELEASE = 620,
EIDCTRLANDLEFTMOUSEWHEEL = 630,
EIDALTANDMOUSEWHEEL = 640,
EIDALTANDMIDDLEMOUSEBTN = 641,
EIDALTANDMIDDLEMOUSEBTNANDMOVE = 642,
EIDALTANDMIDDLEMOUSEBTNRELEASE = 643,
EIDALTANDSHIFTANDRIGHTMOUSEBTN = 644,
EIDALTANDSHIFTANDRIGHTMOUSEBTNANDMOUSEMOVE = 645,
EIDALTANDSHIFTANDRIGHTMOUSEBTNRELEASE = 646,
EIDSHIFTANDRIGHTMOUSEPRESS = 2000,
EIDSHIFTANDRIGHTMOUSEMOVE = 2001,
EIDSHIFTANDRIGHTMOUSERELEASE = 2002,
EIDSHIFTANDMIDDLEMOUSEPRESS = 2003,
EIDSHIFTANDMIDDLEMOUSEMOVE = 2004,
EIDSHIFTANDMIDDLEMOUSERELEASE = 2005,
- EIDSPACENAVIGATORINPUT = 4001, // 3d Mouse, SpaceNavigator input
- EIDSPACENAVIGATORKEYDOWN = 4002, // 3d Mouse, KeyDown
- EIDWIIMOTEINPUT = 4003, // WiiMote input
- EIDWIIMOTEBUTTON = 4004, // WiiMote home button
- EIDWIIMOTEBUTTONB = 4005, // WiiMote b button
EIDSTRGANDN = 10,
EIDSTRGANDE = 11,
EIDDELETE = 12,
EIDN = 13,
EIDESCAPE = 14,
EIDP = 15,
EIDR = 16,
EIDT = 17,
EIDS = 18,
EIDE = 19,
EIDSTRGANDALTANDA = 20,
EIDSTRGANDALTANDB = 21,
EIDH = 22,
EIDRETURN = 23,
EIDENTER = 24,
EIDSPACE = 25,
EIDPLUS = 26,
EIDMINUS = 27,
EIDSTRGANDALTANDH = 30,
EIDSTRGANDALTANDI = 31,
EIDSTRGANDALTANDS = 40,
EIDALT = 90,
EIDSTRGANDB = 91,
EIDNEW = 1000,
EIDOLD = 1001,
EIDFINISHED = 1002,
EIDNO = 1003,
EIDYES = 1004,
EIDSAME = 1005,
EIDNOANDLASTOBJECT = 1006,
EIDNOANDNOTLASTOBJECT = 1007,
EIDLAST = 1008,
EIDNOTLAST = 1009,
EIDSTSMALERNMINUS1 = 1010,
EIDSTLARGERNMINUS1 = 1011,
EIDPOSITIONEVENT = 1012,
EIDEDIT = 1013,
EIDSMALLERN = 1014,
EIDEQUALSN = 1015,
EIDLARGERN = 1016,
EIDEMPTY = 1017,
EIDSUBDESELECT = 1020,
EIDSMTOSELECTED = 1030,
EIDSMTODESELECTED = 1031,
EIDTIP = 1050,
EIDHEAD = 1051,
EIDBODY = 1052,
EIDCLEAR = 1100,
EIDACTIVATETOOL = 1300,
EIDPRINT = 3001,
EV_INIT = 5551001,
EV_PREVIOUS = 5551002,
EV_PATH_COLLECTION_SELECTED = 5551003,
EV_NAVIGATION_SELECTED = 5551004,
EV_LESS_THEN_MIN_COUNT = 5551005,
EV_READY = 5551006,
EV_NEXT = 5551007,
EV_DONE = 5551008,
EV_NEW_LANDMARK = 5551009,
EV_REMOVE_LANDMARK = 5551010,
EIDINSIDE = 2500,
EIDA = 4001,
EIDB = 4002,
EIDC = 4003,
EIDD = 4004,
EIDF = 4005,
EIDG = 4006,
EIDI = 4007,
EIDJ = 4008,
EIDK = 4009,
EIDL = 4010,
EIDM = 4011,
EIDO = 4012,
EIDQ = 4013,
EIDU = 4014,
EIDV = 4015,
EIDW = 4016,
EIDX = 4017,
EIDY = 4018,
EIDZ = 4019,
EID1 = 4020,
EID2 = 4021,
EID3 = 4022,
EID4 = 4023,
EID5 = 4024,
EID6 = 4025,
EID7 = 4026,
EID8 = 4027,
EID9 = 4028,
EID0 = 4029,
EIDFIGUREHOVER = 12340,
EIDNOFIGUREHOVER = 12341
};
//##Constants for Operations
- //## xomments are always examples of the usage
+ //## comments are always examples of the usage
enum EOperations
{
OpNOTHING = 0,
OpTEST = 1,
OpNEWCELL = 10, // add a new cell
OpADD = 100, // add a point or a vessel
OpUNDOADD = 101,
OpADDLINE = 1001, // add a line
OpINSERT = 200, // insert a point at position
OpINSERTLINE = 201, // insert a line at position
OpINSERTPOINT = 202,
OpCLOSECELL = 250, // close a cell (to a polygon)
OpOPENCELL = 251, // close a cell (to a polygon)
OpMOVE = 300, // move a point
OpMOVELINE = 301, // move a line
OpMOVECELL = 302, // move a line
OpUNDOMOVE = 303,
OpMOVEPOINTUP = 304,
OpMOVEPOINTDOWN = 305,
OpREMOVE = 400, // remove a point at position
OpREMOVELINE = 401, // remove a line at position
OpREMOVECELL = 402, // remove a cell
OpREMOVEPOINT = 403,
OpDELETE = 500, // delete
OpDELETELINE = 501, // delete the last line in a cell
OpUNDELETE = 502,
OpDELETECELL = 505,
OpSTATECHANGE = 600, // change a state
OpTIMECHANGE = 601, // change a state
OpTERMINATE = 666, // change a state
OpSELECTPOINT = 700,
OpSELECTLINE = 701,
OpSELECTCELL = 702,
OpSELECTSUBOBJECT = 703, // for VesselGraphInteractor
// OpSELECTNEWSUBOBJECT = 704, //for VesselGraphInteractor
OpSELECT = 705,
OpDESELECTPOINT = 800,
OpDESELECTLINE = 801,
OpDESELECTCELL = 802,
OpDESELECTSUBOBJECT = 803, // for VesselGraphInteractor
OpDESELECTALL = 804, // for VesselGraphInteractor
OpDESELECT = 805,
OpNAVIGATE = 900,
OpZOOM = 1000,
OpSCALE = 1100,
OpROTATE = 1200,
OpORIENT = 1201,
OpRESTOREPLANEPOSITION = 1202,
OpAPPLYTRANSFORMMATRIX = 1203,
OpSETPOINTTYPE = 1210,
OpMODECHANGE = 1500,
OpSENDCOORDINATES = 1600,
OpPERIPHERYSEARCH = 2000, // used in VesselGraphInteractor
OpROOTSEARCH = 2001, // used in VesselGraphInteractor
OpTHICKSTVESSELSEARCH = 2002, // used in VesselGraphInteractor
OpSHORTESTPATHSEARCH = 2003, // used in VesselGraphInteractor
OpATTRIBUTATION = 2004, // used in VesselGraphInteractor
OpDEFAULT = 2006, // used in VesselGraphInteractor
OpSURFACECHANGED = 3000, // used for changing polydata in surfaces
};
//##Constants for EventMapping...
//##connects the statemachine.xml-File with the implemented conditions.
//##within one statemachine the choice of the actionconstants is freely
//##
//## ActionId
enum EActions
{
AcDONOTHING = 0,
AcINITNEWOBJECT = 5,
AcINITEDITOBJECT = 6,
AcINITEDITGROUP = 7,
AcINITMOVEMENT = 8,
AcINITMOVE = 9,
AcINITFOREGROUND = 45, // used in SeedsInteractor for setting the foreground seeds
AcINITBACKGROUND = 46, // used in SeedsInteractor for setting the background seeds
AcINITNEUTRAL = 47, // used in SeedsInteractor for setting the neutral seeds (rubber)
AcINITUPDATE = 1235, // For shape model deformation
AcADDPOINT = 10,
AcADDPOINTRMB = 6000, // in mitralPointSetInteractor used to set a different type of point
AcADD = 11,
AcADDLINE = 12,
AcADDANDFINISH = 13,
AcADDSELECTEDTOGROUP = 64,
AcCHECKPOINT = 21,
AcCHECKLINE = 22,
AcCHECKCELL = 23,
AcCHECKELEMENT = 30, // check if there is a element close enough (picking)
AcCHECKOBJECT = 31, // check if an object is hit
AcCHECKNMINUS1 = 32, // check if the number of elements is equal to N-1
AcCHECKEQUALS1 = 33, // check if the number of elements in the data is equal to 1
AcCHECKNUMBEROFPOINTS = 330, // check the number of elements in the data
AcCHECKSELECTED = 34, // check if the given element is selected or not
AcCHECKONESELECTED = 340, // check if there is an element that is selected
AcCHECKHOVERING = 341, // check if there is an element that is selected
AcCHECKGREATERZERO = 35, // check if the current number of elements is greater than 0
AcCHECKGREATERTWO = 36, // check if the current number of elements is greater than two
AcCHECKOPERATION = 37, // check if the operation is of one spectial type
AcCHECKONESUBINTERACTOR = 38,
AcCHECKSUBINTERACTORS = 39,
AcFINISHOBJECT = 40,
AcFINISHGROUP = 41,
AcFINISHMOVEMENT = 42,
AcFINISHMOVE = 43,
AcFINISH = 44,
AcSEARCHOBJECT = 50,
AcSEARCHGROUP = 51,
AcSEARCHANOTHEROBJECT = 52, // one object is selected and another object is to be added to selection
AcSELECTPICKEDOBJECT = 60, // select the picked object and deselect others
AcSELECTANOTHEROBJECT = 61,
AcSELECTGROUP = 62,
AcSELECTALL = 63,
AcSELECT = 65,
AcSELECTPOINT = 66,
AcSELECTLINE = 68,
AcSELECTCELL = 67,
AcSELECTSUBOBJECT = 69, // used in VesselGraphInteractor
AcDESELECTOBJECT = 70, // deselect picked from group
AcDESELECTALL = 72,
AcDESELECT = 75,
AcDESELECTPOINT = 76,
AcDESELECTLINE = 78,
AcDESELECTCELL = 77,
AcNEWPOINT = 80,
AcNEWSUBOBJECT = 81,
AcMOVEPOINT = 90,
AcMOVESELECTED = 91,
AcMOVE = 92,
AcMOVEPOINTUP = 93,
AcMOVEPOINTDOWN = 94,
AcREMOVEPOINT = 100,
AcREMOVE = 101,
AcREMOVELINE = 102,
AcREMOVEALL = 103,
AcREMOVESELECTEDSUBOBJECT = 104, // used in VesselGraphInteractor
AcWHEEL = 105,
AcPLUS = 106,
AcMINUS = 107,
AcDELETEPOINT = 120,
AcCLEAR = 130, // clear all elements from a list
AcINSERTPOINT = 110,
AcINSERTLINE = 111,
AC_SET_NEXT_BUTTON_VISIBLE = 5550001,
AC_SET_NEXT_BUTTON_INVISIBLE = 5550002,
AC_SET_PREVIOUS_BUTTON_VISIBLE = 5550003,
AC_SET_PREVIOUS_BUTTON_INVISIBLE = 5550004,
AC_SET_ASSISTAND_WIDGET_STECK = 5550005,
AC_SETMAX_COUNT_REF_POINTS = 5550006,
AC_SET_NEXT_BUTTON_TEXT = 5550007,
AC_CHECK_LANDMARK_COUNT = 5550008,
AC_SET_DONE_FALSE = 5550009,
AC_INIT = 55500010,
AC_SET_APPLICATION_SELECTED_FALSE = 55500011,
AC_SENSOR_ATTACHED = 55500012,
AC_CLOSE_ASSISTENT = 55500013,
AC_START_APPLICATION_TEXT = 55500014,
AC_START_NAVIGATION = 55500015,
AC_START_PATHCOLLECTION = 55500016,
AC_LOAD_LANDMARKS = 55500017,
AC_CALCULATE_LANDMARK_TRANSFORM = 55500018,
AcTERMINATE_INTERACTION = 666,
AcTRANSLATESTART = 1000,
AcTRANSLATE = 1001,
AcSCALESTART = 1002,
AcSCALE = 1003,
AcROTATESTART = 1004,
AcROTATE = 1005,
AcINITAFFINEINTERACTIONS = 1006,
AcFINISHAFFINEINTERACTIONS = 1007,
AcTRANSLATEEND = 1008,
AcSCALEEND = 1009,
AcROTATEEND = 1010,
AcINITZOOM = 1011,
AcZOOM = 1012,
AcSCROLL = 1013,
AcLEVELWINDOW = 1014,
AcSCROLLMOUSEWHEEL = 1015,
AcSETSTARTPOINT = 1050,
AcMODEDESELECT = 1100, // set interactor in not selected mode
AcMODESELECT = 1101, // set interactor in selected mode
AcMODESUBSELECT = 1102, // set interacor in sub selected mode
AcINFORMLISTENERS = 1200,
AcASKINTERACTORS = 1201,
AcCHECKGREATERONE = 1500,
AcCHECKBOUNDINGBOX = 1510,
AcFORCESUBINTERACTORS = 1550,
AcSENDCOORDINATES = 1600,
AcTRANSMITEVENT = 2000, // to transmit an event to a lower Interactor/Statemachine
AcPERIPHERYSEARCH = 3000, // used in VesselGraphInteractor
AcROOTSEARCH = 3001, // used in VesselGraphInteractor
AcTHICKSTVESSELSEARCH = 3002, // used in VesselGraphInteractor
AcSHORTESTPATHSEARCH = 3003, // used in VesselGraphInteractor
AcSINGLE = 3004, // used in VesselGraphInteractor
AcATTRIBUTATION = 3005, // used in VesselGraphInteractor
AcDEFAULT = 3007, // used in VesselGraphInteractor
AcSETVESSELELEMENT = 3008, // used in VesselGraphInteractor
AcCHECKBARRIERSTATUS = 3010, // used in VesselGraphInteractor
AcUPDATEMESH = 1234, // For Shape Model Interaction
AcINCREASE = 49012,
AcDECREASE = 49013,
AcMODIFY = 49014,
AcUNDOUPDATE = 1236, // For restoring a mesh after an update
AcENTEROBJECT = 48000,
AcLEAVEOBJECT = 48001,
AcSWITCHOBJECT = 48002,
AcUPDATELINE = 48003,
AcINITLINE = 48004,
AcTERMINATELINE = 48005,
AcCREATEBOX = 48006,
AcCREATEOBJECTFROMLINE = 48007,
AcCANCEL = 48008,
AcACTIVATETOOL = 48009,
AcROTATEAROUNDPOINT1 = 49002,
AcROTATEAROUNDPOINT2 = 49003,
AcMOVEPOINT1 = 49004,
AcMOVEPOINT2 = 49005,
AcUPDATEPOINT = 49006,
AcUPDATERADIUSMOUSEWHEEL = 49007,
AcDISPLAYOPTIONS = 49009,
AcCYCLE = 49010,
AcACCEPT = 49011,
- AcONSPACENAVIGATORMOUSEINPUT = 4001, // On input of 3D Mouse
- AcONPACENAVIGATORKEYDOWN = 4002, // On input of 3D Mouse
- AcONWIIMOTEINPUT = 4003, // used for wiimote to signal IR input
- AcRESETVIEW = 4004, // used for wiimote to reset view
- AcONWIIMOTEBUTTONRELEASED = 4005, // stops the surface interaction
AcCHECKPOSITION = 5000,
AcINITIALIZECONTOUR = 5001,
AcCALCULATENEWSEGMENTATION_SP = 5002,
AcINTERACTOR = 5003,
AcCALCULATENEWSEGMENTATION_BB = 5004
};
/*
//!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!
//EventMechanism:
//If you change anything from here on, then change in mitkEventMapper.cpp (Array of constants) as well.
//!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!
*/
// Type of an Event;
enum EEventType
{
Type_None = 0, // invalid event
Type_Timer = 1, // timer event
Type_MouseButtonPress = 2, // mouse button pressed
Type_MouseButtonRelease = 3, // mouse button released
Type_MouseButtonDblClick = 4, // mouse button double click
Type_MouseMove = 5, // mouse move
Type_KeyPress = 6, // key pressed
Type_KeyRelease = 7, // key released
Type_FocusIn = 8, // keyboard focus received
Type_FocusOut = 9, // keyboard focus lost
Type_Enter = 10, // mouse enters widget
Type_Leave = 11, // mouse leaves widget
Type_Paint = 12, // paint widget
Type_Move = 13, // move widget
Type_Resize = 14, // resize widget
Type_Create = 15, // after object creation
Type_Destroy = 16, // during object destruction
Type_Show = 17, // widget is shown
Type_Hide = 18, // widget is hidden
Type_Close = 19, // request to close widget
Type_Quit = 20, // request to quit application
Type_Reparent = 21, // widget has been reparented
Type_ShowMinimized = 22, // widget is shown minimized
Type_ShowNormal = 23, // widget is shown normal
Type_WindowActivate = 24, // window was activated
Type_WindowDeactivate = 25, // window was deactivated
Type_ShowToParent = 26, // widget is shown to parent
Type_HideToParent = 27, // widget is hidden to parent
Type_ShowMaximized = 28, // widget is shown maximized
Type_ShowFullScreen = 29, // widget is shown full-screen
Type_Accel = 30, // accelerator event
Type_Wheel = 31, // wheel event
Type_AccelAvailable = 32, // accelerator available event
Type_CaptionChange = 33, // caption changed
Type_IconChange = 34, // icon changed
Type_ParentFontChange = 35, // parent font changed
Type_ApplicationFontChange = 36, // application font changed
Type_ParentPaletteChange = 37, // parent palette changed
Type_ApplicationPaletteChange = 38, // application palette changed
Type_PaletteChange = 39, // widget palette changed
Type_Clipboard = 40, // internal clipboard event
Type_Speech = 42, // reserved for speech input
Type_SockAct = 50, // socket activation
Type_AccelOverride = 51, // accelerator override event
Type_DeferredDelete = 52, // deferred delete event
Type_DragEnter = 60, // drag moves into widget
Type_DragMove = 61, // drag moves in widget
Type_DragLeave = 62, // drag leaves or is cancelled
Type_Drop = 63, // actual drop
Type_DragResponse = 64, // drag accepted/rejected
Type_ChildInserted = 70, // new child widget
Type_ChildRemoved = 71, // deleted child widget
Type_LayoutHint = 72, // child min/max size changed
Type_ShowWindowRequest = 73, // widget's window should be mapped
Type_ActivateControl = 80, // ActiveX activation
Type_DeactivateControl = 81, // ActiveX deactivation
Type_ContextMenu = 82, // context popup menu
Type_IMStart = 83, // input method composition start
Type_IMCompose = 84, // input method composition
Type_IMEnd = 85, // input method composition end
Type_Accessibility = 86, // accessibility information is requested
Type_TabletMove = 87, // Wacom tablet event
Type_LocaleChange = 88, // the system locale changed
Type_LanguageChange = 89, // the application language changed
Type_LayoutDirectionChange = 90, // the layout direction changed
Type_Style = 91, // internal style event
Type_TabletPress = 92, // tablet press
Type_TabletRelease = 93, // tablet release
Type_User = 1000, // first user event id
- Type_SpaceNavigatorInput = 1094, // 3D mouse input occurred
- Type_SpaceNavigatorKeyDown = 1095, // 3D mouse input occurred
- Type_WiiMoteInput = 1096, // WiiMote input occurred
- Type_WiiMoteButton = 1097, // WiiMote button pressed
Type_MaxUser = 65535
};
//##ButtonState
// mouse/keyboard state values
// QT combinations if MOUSEBUTTONRelease: left MouseButton + ControlButton: 0x201
enum EButtonStates
{
BS_NoButton = 0x0000,
BS_LeftButton = 0x0001,
BS_RightButton = 0x0002,
BS_MidButton = 0x0004,
BS_MouseButtonMask = 0x0007,
BS_ShiftButton = 0x0100,
BS_ControlButton = 0x0200,
BS_AltButton = 0x0400,
BS_MetaButton = 0x0800,
BS_KeyButtonMask = 0x0f00,
BS_Keypad = 0x4000
};
//##Key
enum EKeys
{
Key_Escape = 0x1000, // misc keys
Key_Tab = 0x1001,
Key_Backtab = 0x1002,
Key_BackTab = 0x1002, //= Key_Backtab
Key_Backspace = 0x1003,
Key_BackSpace = 0x1003, //= Key_Backspace
Key_Return = 0x1004,
Key_Enter = 0x1005,
Key_Insert = 0x1006,
Key_Delete = 0x1007,
Key_Pause = 0x1008,
Key_Print = 0x1009,
Key_SysReq = 0x100a,
Key_Home = 0x1010, // cursor movement
Key_End = 0x1011,
Key_Left = 0x1012,
Key_Up = 0x1013,
Key_Right = 0x1014,
Key_Down = 0x1015,
Key_Prior = 0x1016,
Key_PageUp = 0x1016, //=Key_Prior
Key_Next = 0x1017,
Key_PageDown = 0x1017, //=Key_Next
Key_Shift = 0x1020, // modifiers
Key_Control = 0x1021,
Key_Meta = 0x1022,
Key_Alt = 0x1023,
Key_CapsLock = 0x1024,
Key_NumLock = 0x1025,
Key_ScrollLock = 0x1026,
Key_F1 = 0x1030, // function keys
Key_F2 = 0x1031,
Key_F3 = 0x1032,
Key_F4 = 0x1033,
Key_F5 = 0x1034,
Key_F6 = 0x1035,
Key_F7 = 0x1036,
Key_F8 = 0x1037,
Key_F9 = 0x1038,
Key_F10 = 0x1039,
Key_F11 = 0x103a,
Key_F12 = 0x103b,
Key_F13 = 0x103c,
Key_F14 = 0x103d,
Key_F15 = 0x103e,
Key_F16 = 0x103f,
Key_F17 = 0x1040,
Key_F18 = 0x1041,
Key_F19 = 0x1042,
Key_F20 = 0x1043,
Key_F21 = 0x1044,
Key_F22 = 0x1045,
Key_F23 = 0x1046,
Key_F24 = 0x1047,
Key_F25 = 0x1048, // F25 .. F35 only on X11
Key_F26 = 0x1049,
Key_F27 = 0x104a,
Key_F28 = 0x104b,
Key_F29 = 0x104c,
Key_F30 = 0x104d,
Key_F31 = 0x104e,
Key_F32 = 0x104f,
Key_F33 = 0x1050,
Key_F34 = 0x1051,
Key_F35 = 0x1052,
Key_Super_L = 0x1053, // extra keys
Key_Super_R = 0x1054,
Key_Menu = 0x1055,
Key_Hyper_L = 0x1056,
Key_Hyper_R = 0x1057,
Key_Help = 0x1058,
// International input method support (X keycode - = 0xEE00)
// Only interesting if you are writing your own input method
Key_Muhenkan = 0x1122, // Cancel Conversion
Key_Henkan = 0x1123, // Start/Stop Conversion
Key_Hiragana_Katakana = 0x1127, // Hiragana/Katakana toggle
Key_Zenkaku_Hankaku = 0x112A, // Zenkaku/Hankaku toggle
Key_Space = 0x20, // 7 bit printable ASCII
Key_Any = 0x20, //= Key_Space
Key_Exclam = 0x21,
Key_QuoteDbl = 0x22,
Key_NumberSign = 0x23,
Key_Dollar = 0x24,
Key_Percent = 0x25,
Key_Ampersand = 0x26,
Key_Apostrophe = 0x27,
Key_ParenLeft = 0x28,
Key_ParenRight = 0x29,
Key_Asterisk = 0x2a,
Key_Plus = 0x2b,
Key_Comma = 0x2c,
Key_Minus = 0x2d,
Key_Period = 0x2e,
Key_Slash = 0x2f,
Key_0 = 0x30,
Key_1 = 0x31,
Key_2 = 0x32,
Key_3 = 0x33,
Key_4 = 0x34,
Key_5 = 0x35,
Key_6 = 0x36,
Key_7 = 0x37,
Key_8 = 0x38,
Key_9 = 0x39,
Key_Colon = 0x3a,
Key_Semicolon = 0x3b,
Key_Less = 0x3c,
Key_Equal = 0x3d,
Key_Greater = 0x3e,
Key_Question = 0x3f,
Key_At = 0x40,
Key_A = 0x41,
Key_B = 0x42,
Key_C = 0x43,
Key_D = 0x44,
Key_E = 0x45,
Key_F = 0x46,
Key_G = 0x47,
Key_H = 0x48,
Key_I = 0x49,
Key_J = 0x4a,
Key_K = 0x4b,
Key_L = 0x4c,
Key_M = 0x4d,
Key_N = 0x4e,
Key_O = 0x4f,
Key_P = 0x50,
Key_Q = 0x51,
Key_R = 0x52,
Key_S = 0x53,
Key_T = 0x54,
Key_U = 0x55,
Key_V = 0x56,
Key_W = 0x57,
Key_X = 0x58,
Key_Y = 0x59,
Key_Z = 0x5a,
Key_BracketLeft = 0x5b,
Key_Backslash = 0x5c,
Key_BracketRight = 0x5d,
Key_AsciiCircum = 0x5e,
Key_Underscore = 0x5f,
Key_QuoteLeft = 0x60,
Key_BraceLeft = 0x7b,
Key_Bar = 0x7c,
Key_BraceRight = 0x7d,
Key_AsciiTilde = 0x7e,
Key_nobreakspace = 0x0a0,
Key_exclamdown = 0x0a1,
Key_cent = 0x0a2,
Key_sterling = 0x0a3,
Key_currency = 0x0a4,
Key_yen = 0x0a5,
Key_brokenbar = 0x0a6,
Key_section = 0x0a7,
Key_diaeresis = 0x0a8,
Key_copyright = 0x0a9,
Key_ordfeminine = 0x0aa,
Key_guillemotleft = 0x0ab, // left angle quotation mark
Key_notsign = 0x0ac,
Key_hyphen = 0x0ad,
Key_registered = 0x0ae,
Key_macron = 0x0af,
Key_degree = 0x0b0,
Key_plusminus = 0x0b1,
Key_twosuperior = 0x0b2,
Key_threesuperior = 0x0b3,
Key_acute = 0x0b4,
Key_mu = 0x0b5,
Key_paragraph = 0x0b6,
Key_periodcentered = 0x0b7,
Key_cedilla = 0x0b8,
Key_onesuperior = 0x0b9,
Key_masculine = 0x0ba,
Key_guillemotright = 0x0bb, // right angle quotation mark
Key_onequarter = 0x0bc,
Key_onehalf = 0x0bd,
Key_threequarters = 0x0be,
Key_questiondown = 0x0bf,
Key_Agrave = 0x0c0,
Key_Aacute = 0x0c1,
Key_Acircumflex = 0x0c2,
Key_Atilde = 0x0c3,
Key_Adiaeresis = 0x0c4,
Key_Aring = 0x0c5,
Key_AE = 0x0c6,
Key_Ccedilla = 0x0c7,
Key_Egrave = 0x0c8,
Key_Eacute = 0x0c9,
Key_Ecircumflex = 0x0ca,
Key_Ediaeresis = 0x0cb,
Key_Igrave = 0x0cc,
Key_Iacute = 0x0cd,
Key_Icircumflex = 0x0ce,
Key_Idiaeresis = 0x0cf,
Key_ETH = 0x0d0,
Key_Ntilde = 0x0d1,
Key_Ograve = 0x0d2,
Key_Oacute = 0x0d3,
Key_Ocircumflex = 0x0d4,
Key_Otilde = 0x0d5,
Key_Odiaeresis = 0x0d6,
Key_multiply = 0x0d7,
Key_Ooblique = 0x0d8,
Key_Ugrave = 0x0d9,
Key_Uacute = 0x0da,
Key_Ucircumflex = 0x0db,
Key_Udiaeresis = 0x0dc,
Key_Yacute = 0x0dd,
Key_THORN = 0x0de,
Key_ssharp = 0x0df,
Key_agrave = 0x0e0,
Key_aacute = 0x0e1,
Key_acircumflex = 0x0e2,
Key_atilde = 0x0e3,
Key_adiaeresis = 0x0e4,
Key_aring = 0x0e5,
Key_ae = 0x0e6,
Key_ccedilla = 0x0e7,
Key_egrave = 0x0e8,
Key_eacute = 0x0e9,
Key_ecircumflex = 0x0ea,
Key_ediaeresis = 0x0eb,
Key_igrave = 0x0ec,
Key_iacute = 0x0ed,
Key_icircumflex = 0x0ee,
Key_idiaeresis = 0x0ef,
Key_eth = 0x0f0,
Key_ntilde = 0x0f1,
Key_ograve = 0x0f2,
Key_oacute = 0x0f3,
Key_ocircumflex = 0x0f4,
Key_otilde = 0x0f5,
Key_odiaeresis = 0x0f6,
Key_division = 0x0f7,
Key_oslash = 0x0f8,
Key_ugrave = 0x0f9,
Key_uacute = 0x0fa,
Key_ucircumflex = 0x0fb,
Key_udiaeresis = 0x0fc,
Key_yacute = 0x0fd,
Key_thorn = 0x0fe,
Key_ydiaeresis = 0x0ff,
Key_unknown = 0xffff,
Key_none = 0xffff //= Key_unknown
};
} // namespace mitk
#endif
diff --git a/Modules/Core/src/Rendering/mitkPointSetVtkMapper3D.cpp b/Modules/Core/src/Rendering/mitkPointSetVtkMapper3D.cpp
index 8c30df1c50..beafa5cc99 100644
--- a/Modules/Core/src/Rendering/mitkPointSetVtkMapper3D.cpp
+++ b/Modules/Core/src/Rendering/mitkPointSetVtkMapper3D.cpp
@@ -1,614 +1,594 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkPointSetVtkMapper3D.h"
#include "mitkColorProperty.h"
#include "mitkDataNode.h"
#include "mitkPointSet.h"
#include "mitkProperties.h"
#include "mitkVtkPropRenderer.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
const mitk::PointSet *mitk::PointSetVtkMapper3D::GetInput()
{
return static_cast(GetDataNode()->GetData());
}
mitk::PointSetVtkMapper3D::PointSetVtkMapper3D()
: m_vtkSelectedPointList(nullptr),
m_vtkUnselectedPointList(nullptr),
m_VtkSelectedPolyDataMapper(nullptr),
m_VtkUnselectedPolyDataMapper(nullptr),
m_vtkTextList(nullptr),
m_NumberOfSelectedAdded(0),
m_NumberOfUnselectedAdded(0),
m_PointSize(1.0),
m_ContourRadius(0.5)
{
// propassembly
m_PointsAssembly = vtkSmartPointer::New();
// creating actors to be able to set transform
m_SelectedActor = vtkSmartPointer::New();
m_UnselectedActor = vtkSmartPointer::New();
m_ContourActor = vtkSmartPointer::New();
}
mitk::PointSetVtkMapper3D::~PointSetVtkMapper3D()
{
}
void mitk::PointSetVtkMapper3D::ReleaseGraphicsResources(vtkWindow *renWin)
{
m_PointsAssembly->ReleaseGraphicsResources(renWin);
m_SelectedActor->ReleaseGraphicsResources(renWin);
m_UnselectedActor->ReleaseGraphicsResources(renWin);
m_ContourActor->ReleaseGraphicsResources(renWin);
}
void mitk::PointSetVtkMapper3D::ReleaseGraphicsResources(mitk::BaseRenderer *renderer)
{
m_PointsAssembly->ReleaseGraphicsResources(renderer->GetRenderWindow());
m_SelectedActor->ReleaseGraphicsResources(renderer->GetRenderWindow());
m_UnselectedActor->ReleaseGraphicsResources(renderer->GetRenderWindow());
m_ContourActor->ReleaseGraphicsResources(renderer->GetRenderWindow());
}
void mitk::PointSetVtkMapper3D::CreateVTKRenderObjects()
{
m_vtkSelectedPointList = vtkSmartPointer::New();
m_vtkUnselectedPointList = vtkSmartPointer::New();
m_PointsAssembly->VisibilityOn();
if (m_PointsAssembly->GetParts()->IsItemPresent(m_SelectedActor))
m_PointsAssembly->RemovePart(m_SelectedActor);
if (m_PointsAssembly->GetParts()->IsItemPresent(m_UnselectedActor))
m_PointsAssembly->RemovePart(m_UnselectedActor);
if (m_PointsAssembly->GetParts()->IsItemPresent(m_ContourActor))
m_PointsAssembly->RemovePart(m_ContourActor);
- // exceptional displaying for PositionTracker -> MouseOrientationTool
- int mapperID;
- bool isInputDevice = false;
- if (this->GetDataNode()->GetBoolProperty("inputdevice", isInputDevice) && isInputDevice)
- {
- if (this->GetDataNode()->GetIntProperty("BaseRendererMapperID", mapperID) && mapperID == BaseRenderer::Standard3D)
- return; // The event for the PositionTracker came from the 3d widget and not needs to be displayed
- }
-
// get and update the PointSet
mitk::PointSet::Pointer input = const_cast(this->GetInput());
/* only update the input data, if the property tells us to */
bool update = true;
this->GetDataNode()->GetBoolProperty("updateDataOnRender", update);
if (update == true)
input->Update();
int timestep = this->GetTimestep();
mitk::PointSet::DataType::Pointer itkPointSet = input->GetPointSet(timestep);
if (itkPointSet.GetPointer() == nullptr)
{
m_PointsAssembly->VisibilityOff();
return;
}
// now fill selected and unselected pointList
// get size of Points in Property
m_PointSize = 2;
mitk::FloatProperty::Pointer pointSizeProp =
dynamic_cast(this->GetDataNode()->GetProperty("pointsize"));
if (pointSizeProp.IsNotNull())
m_PointSize = pointSizeProp->GetValue();
// get the property for creating a label onto every point only once
bool showLabel = true;
this->GetDataNode()->GetBoolProperty("show label", showLabel);
const char *pointLabel = nullptr;
if (showLabel)
{
if (dynamic_cast(this->GetDataNode()->GetPropertyList()->GetProperty("label")) != nullptr)
pointLabel =
dynamic_cast(this->GetDataNode()->GetPropertyList()->GetProperty("label"))->GetValue();
else
showLabel = false;
}
// whether or not to creat a "contour" - connecting lines between all the points
int nbPoints = itkPointSet->GetPointData()->Size();
bool makeContour = false;
this->GetDataNode()->GetBoolProperty("show contour", makeContour);
bool closeContour = false;
this->GetDataNode()->GetBoolProperty("close contour", closeContour);
int contourPointLimit = 0; // NO contour
if (makeContour)
{
if (closeContour)
contourPointLimit = nbPoints;
else
contourPointLimit = nbPoints - 1;
}
// build list of all positions for later transform in one go
mitk::PointSet::PointsContainer::Iterator pointsIter;
int ptIdx;
m_NumberOfSelectedAdded = 0;
m_NumberOfUnselectedAdded = 0;
vtkSmartPointer localPoints = vtkSmartPointer::New();
m_WorldPositions = vtkSmartPointer::New();
m_PointConnections = vtkSmartPointer::New(); // m_PointConnections between points
for (ptIdx = 0, pointsIter = itkPointSet->GetPoints()->Begin(); pointsIter != itkPointSet->GetPoints()->End();
pointsIter++, ptIdx++)
{
itk::Point currentPoint = pointsIter->Value();
localPoints->InsertPoint(ptIdx, currentPoint[0], currentPoint[1], currentPoint[2]);
if (makeContour && ptIdx < contourPointLimit)
{
vtkIdType cell[2] = {(ptIdx + 1) % nbPoints, ptIdx};
m_PointConnections->InsertNextCell(2, cell);
}
}
vtkSmartPointer vtktransform = this->GetDataNode()->GetVtkTransform(this->GetTimestep());
vtktransform->TransformPoints(localPoints, m_WorldPositions);
// create contour
if (makeContour)
{
this->CreateContour(m_WorldPositions, m_PointConnections);
}
// check if the list for the PointDataContainer is the same size as the PointsContainer. Is not, then the points were
// inserted manually and can not be visualized according to the PointData (selected/unselected)
bool pointDataBroken = (itkPointSet->GetPointData()->Size() != itkPointSet->GetPoints()->Size());
// now add an object for each point in data
mitk::PointSet::PointDataContainer::Iterator pointDataIter = itkPointSet->GetPointData()->Begin();
for (ptIdx = 0; ptIdx < nbPoints; ++ptIdx) // pointDataIter moved at end of loop
{
double currentPoint[3];
m_WorldPositions->GetPoint(ptIdx, currentPoint);
vtkSmartPointer source;
// check for the pointtype in data and decide which geom-object to take and then add to the selected or unselected
// list
int pointType;
if (itkPointSet->GetPointData()->size() == 0 || pointDataBroken)
pointType = mitk::PTUNDEFINED;
else
pointType = pointDataIter.Value().pointSpec;
switch (pointType)
{
case mitk::PTUNDEFINED:
{
vtkSmartPointer sphere = vtkSmartPointer::New();
sphere->SetRadius(m_PointSize / 2.0f);
sphere->SetCenter(currentPoint);
- // sphere->SetCenter(pointsIter.Value()[0],pointsIter.Value()[1],pointsIter.Value()[2]);
-
- // MouseOrientation Tool (PositionTracker)
- if (isInputDevice)
- {
- sphere->SetThetaResolution(10);
- sphere->SetPhiResolution(10);
- }
- else
- {
- sphere->SetThetaResolution(20);
- sphere->SetPhiResolution(20);
- }
+ sphere->SetThetaResolution(20);
+ sphere->SetPhiResolution(20);
source = sphere;
}
break;
case mitk::PTSTART:
{
vtkSmartPointer cube = vtkSmartPointer::New();
cube->SetXLength(m_PointSize / 2);
cube->SetYLength(m_PointSize / 2);
cube->SetZLength(m_PointSize / 2);
cube->SetCenter(currentPoint);
source = cube;
}
break;
case mitk::PTCORNER:
{
vtkSmartPointer cone = vtkSmartPointer::New();
cone->SetRadius(m_PointSize / 2.0f);
cone->SetCenter(currentPoint);
cone->SetResolution(20);
source = cone;
}
break;
case mitk::PTEDGE:
{
vtkSmartPointer cylinder = vtkSmartPointer::New();
cylinder->SetRadius(m_PointSize / 2.0f);
cylinder->SetCenter(currentPoint);
cylinder->SetResolution(20);
source = cylinder;
}
break;
case mitk::PTEND:
{
vtkSmartPointer sphere = vtkSmartPointer::New();
sphere->SetRadius(m_PointSize / 2.0f);
// no SetCenter?? this functionality should be explained!
// otherwise: join with default block!
sphere->SetThetaResolution(20);
sphere->SetPhiResolution(20);
source = sphere;
}
break;
default:
{
vtkSmartPointer sphere = vtkSmartPointer::New();
sphere->SetRadius(m_PointSize / 2.0f);
sphere->SetCenter(currentPoint);
sphere->SetThetaResolution(20);
sphere->SetPhiResolution(20);
source = sphere;
}
break;
}
if (pointDataIter.Value().selected && !pointDataBroken)
{
m_vtkSelectedPointList->AddInputConnection(source->GetOutputPort());
++m_NumberOfSelectedAdded;
}
else
{
m_vtkUnselectedPointList->AddInputConnection(source->GetOutputPort());
++m_NumberOfUnselectedAdded;
}
if (showLabel)
{
char buffer[20];
std::string l = pointLabel;
if (input->GetSize() > 1)
{
sprintf(buffer, "%d", ptIdx + 1);
l.append(buffer);
}
// Define the text for the label
vtkSmartPointer label = vtkSmartPointer::New();
label->SetText(l.c_str());
//# Set up a transform to move the label to a new position.
vtkSmartPointer aLabelTransform = vtkSmartPointer::New();
aLabelTransform->Identity();
aLabelTransform->Translate(currentPoint[0] + 2, currentPoint[1] + 2, currentPoint[2]);
aLabelTransform->Scale(5.7, 5.7, 5.7);
//# Move the label to a new position.
vtkSmartPointer labelTransform = vtkSmartPointer::New();
labelTransform->SetTransform(aLabelTransform);
labelTransform->SetInputConnection(label->GetOutputPort());
// add it to the wright PointList
if (pointType)
{
m_vtkSelectedPointList->AddInputConnection(labelTransform->GetOutputPort());
++m_NumberOfSelectedAdded;
}
else
{
m_vtkUnselectedPointList->AddInputConnection(labelTransform->GetOutputPort());
++m_NumberOfUnselectedAdded;
}
}
if (pointDataIter != itkPointSet->GetPointData()->End())
pointDataIter++;
} // end FOR
// now according to number of elements added to selected or unselected, build up the rendering pipeline
if (m_NumberOfSelectedAdded > 0)
{
m_VtkSelectedPolyDataMapper = vtkSmartPointer::New();
m_VtkSelectedPolyDataMapper->SetInputConnection(m_vtkSelectedPointList->GetOutputPort());
// create a new instance of the actor
m_SelectedActor = vtkSmartPointer::New();
m_SelectedActor->SetMapper(m_VtkSelectedPolyDataMapper);
m_PointsAssembly->AddPart(m_SelectedActor);
}
if (m_NumberOfUnselectedAdded > 0)
{
m_VtkUnselectedPolyDataMapper = vtkSmartPointer::New();
m_VtkUnselectedPolyDataMapper->SetInputConnection(m_vtkUnselectedPointList->GetOutputPort());
// create a new instance of the actor
m_UnselectedActor = vtkSmartPointer::New();
m_UnselectedActor->SetMapper(m_VtkUnselectedPolyDataMapper);
m_PointsAssembly->AddPart(m_UnselectedActor);
}
}
void mitk::PointSetVtkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer)
{
bool visible = true;
GetDataNode()->GetVisibility(visible, renderer, "visible");
if (!visible)
{
m_UnselectedActor->VisibilityOff();
m_SelectedActor->VisibilityOff();
m_ContourActor->VisibilityOff();
return;
}
// create new vtk render objects (e.g. sphere for a point)
BaseLocalStorage *ls = m_LSH.GetLocalStorage(renderer);
bool needGenerateData = ls->IsGenerateDataRequired(renderer, this, GetDataNode());
if (!needGenerateData)
{
if (this->GetDataNode()->GetPropertyList()->GetMTime() > ls->GetLastGenerateDataTime() ||
this->GetDataNode()->GetPropertyList(renderer)->GetMTime() > ls->GetLastGenerateDataTime())
{
needGenerateData = true;
}
}
if (needGenerateData)
{
this->CreateVTKRenderObjects();
ls->UpdateGenerateDataTime();
}
this->ApplyAllProperties(renderer, m_ContourActor);
bool showPoints = true;
this->GetDataNode()->GetBoolProperty("show points", showPoints);
m_UnselectedActor->SetVisibility(showPoints);
m_SelectedActor->SetVisibility(showPoints);
if (false && dynamic_cast(this->GetDataNode()->GetProperty("opacity")) != nullptr)
{
mitk::FloatProperty::Pointer pointOpacity =
dynamic_cast(this->GetDataNode()->GetProperty("opacity"));
float opacity = pointOpacity->GetValue();
m_ContourActor->GetProperty()->SetOpacity(opacity);
m_UnselectedActor->GetProperty()->SetOpacity(opacity);
m_SelectedActor->GetProperty()->SetOpacity(opacity);
}
bool showContour = false;
this->GetDataNode()->GetBoolProperty("show contour", showContour);
m_ContourActor->SetVisibility(showContour);
}
void mitk::PointSetVtkMapper3D::ResetMapper(BaseRenderer * /*renderer*/)
{
m_PointsAssembly->VisibilityOff();
}
vtkProp *mitk::PointSetVtkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/)
{
return m_PointsAssembly;
}
void mitk::PointSetVtkMapper3D::UpdateVtkTransform(mitk::BaseRenderer * /*renderer*/)
{
}
void mitk::PointSetVtkMapper3D::ApplyAllProperties(mitk::BaseRenderer *renderer, vtkActor *actor)
{
Superclass::ApplyColorAndOpacityProperties(renderer, actor);
// check for color props and use it for rendering of selected/unselected points and contour
// due to different params in VTK (double/float) we have to convert!
// vars to convert to
double unselectedColor[4] = {1.0f, 1.0f, 0.0f, 1.0f}; // yellow
double selectedColor[4] = {1.0f, 0.0f, 0.0f, 1.0f}; // red
double contourColor[4] = {1.0f, 0.0f, 0.0f, 1.0f}; // red
// different types for color!!!
mitk::Color tmpColor;
double opacity = 1.0;
// check if there is an unselected property
if (dynamic_cast(
this->GetDataNode()->GetPropertyList(renderer)->GetProperty("unselectedcolor")) != nullptr)
{
tmpColor = dynamic_cast(
this->GetDataNode()->GetPropertyList(renderer)->GetProperty("unselectedcolor"))
->GetValue();
unselectedColor[0] = tmpColor[0];
unselectedColor[1] = tmpColor[1];
unselectedColor[2] = tmpColor[2];
unselectedColor[3] = 1.0f; //!!define a new ColorProp to be able to pass alpha value
}
else if (dynamic_cast(
this->GetDataNode()->GetPropertyList(nullptr)->GetProperty("unselectedcolor")) != nullptr)
{
tmpColor =
dynamic_cast(this->GetDataNode()->GetPropertyList(nullptr)->GetProperty("unselectedcolor"))
->GetValue();
unselectedColor[0] = tmpColor[0];
unselectedColor[1] = tmpColor[1];
unselectedColor[2] = tmpColor[2];
unselectedColor[3] = 1.0f; //!!define a new ColorProp to be able to pass alpha value
}
else
{
// check if the node has a color
float unselectedColorTMP[4] = {1.0f, 1.0f, 0.0f, 1.0f}; // yellow
m_DataNode->GetColor(unselectedColorTMP, nullptr);
unselectedColor[0] = unselectedColorTMP[0];
unselectedColor[1] = unselectedColorTMP[1];
unselectedColor[2] = unselectedColorTMP[2];
// unselectedColor[3] stays 1.0f
}
// get selected property
if (dynamic_cast(
this->GetDataNode()->GetPropertyList(renderer)->GetProperty("selectedcolor")) != nullptr)
{
tmpColor =
dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("selectedcolor"))
->GetValue();
selectedColor[0] = tmpColor[0];
selectedColor[1] = tmpColor[1];
selectedColor[2] = tmpColor[2];
selectedColor[3] = 1.0f;
}
else if (dynamic_cast(
this->GetDataNode()->GetPropertyList(nullptr)->GetProperty("selectedcolor")) != nullptr)
{
tmpColor =
dynamic_cast(this->GetDataNode()->GetPropertyList(nullptr)->GetProperty("selectedcolor"))
->GetValue();
selectedColor[0] = tmpColor[0];
selectedColor[1] = tmpColor[1];
selectedColor[2] = tmpColor[2];
selectedColor[3] = 1.0f;
}
// get contour property
if (dynamic_cast(
this->GetDataNode()->GetPropertyList(renderer)->GetProperty("contourcolor")) != nullptr)
{
tmpColor =
dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("contourcolor"))
->GetValue();
contourColor[0] = tmpColor[0];
contourColor[1] = tmpColor[1];
contourColor[2] = tmpColor[2];
contourColor[3] = 1.0f;
}
else if (dynamic_cast(
this->GetDataNode()->GetPropertyList(nullptr)->GetProperty("contourcolor")) != nullptr)
{
tmpColor =
dynamic_cast(this->GetDataNode()->GetPropertyList(nullptr)->GetProperty("contourcolor"))
->GetValue();
contourColor[0] = tmpColor[0];
contourColor[1] = tmpColor[1];
contourColor[2] = tmpColor[2];
contourColor[3] = 1.0f;
}
if (dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("opacity")) !=
nullptr)
{
mitk::FloatProperty::Pointer pointOpacity =
dynamic_cast(this->GetDataNode()->GetPropertyList(renderer)->GetProperty("opacity"));
opacity = pointOpacity->GetValue();
}
else if (dynamic_cast(this->GetDataNode()->GetPropertyList(nullptr)->GetProperty("opacity")) !=
nullptr)
{
mitk::FloatProperty::Pointer pointOpacity =
dynamic_cast(this->GetDataNode()->GetPropertyList(nullptr)->GetProperty("opacity"));
opacity = pointOpacity->GetValue();
}
// finished color / opacity fishing!
// check if a contour shall be drawn
bool showContour = false;
this->GetDataNode()->GetBoolProperty("show contour", showContour, renderer);
if (showContour && (m_ContourActor != nullptr))
{
this->CreateContour(m_WorldPositions, m_PointConnections);
m_ContourActor->GetProperty()->SetColor(contourColor);
m_ContourActor->GetProperty()->SetOpacity(opacity);
}
m_SelectedActor->GetProperty()->SetColor(selectedColor);
m_SelectedActor->GetProperty()->SetOpacity(opacity);
m_UnselectedActor->GetProperty()->SetColor(unselectedColor);
m_UnselectedActor->GetProperty()->SetOpacity(opacity);
}
void mitk::PointSetVtkMapper3D::CreateContour(vtkPoints *points, vtkCellArray *m_PointConnections)
{
vtkSmartPointer vtkContourPolyData = vtkSmartPointer::New();
vtkSmartPointer vtkContourPolyDataMapper = vtkSmartPointer::New();
vtkSmartPointer contour = vtkSmartPointer::New();
contour->SetPoints(points);
contour->SetLines(m_PointConnections);
vtkSmartPointer tubeFilter = vtkSmartPointer::New();
tubeFilter->SetNumberOfSides(12);
tubeFilter->SetInputData(contour);
// check for property contoursize.
m_ContourRadius = 0.5;
mitk::FloatProperty::Pointer contourSizeProp =
dynamic_cast(this->GetDataNode()->GetProperty("contoursize"));
if (contourSizeProp.IsNotNull())
m_ContourRadius = contourSizeProp->GetValue();
tubeFilter->SetRadius(m_ContourRadius);
tubeFilter->Update();
// add to pipeline
vtkContourPolyData->AddInputConnection(tubeFilter->GetOutputPort());
vtkContourPolyDataMapper->SetInputConnection(vtkContourPolyData->GetOutputPort());
m_ContourActor->SetMapper(vtkContourPolyDataMapper);
m_PointsAssembly->AddPart(m_ContourActor);
}
void mitk::PointSetVtkMapper3D::SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite)
{
node->AddProperty("line width", mitk::IntProperty::New(2), renderer, overwrite);
node->AddProperty("pointsize", mitk::FloatProperty::New(1.0), renderer, overwrite);
node->AddProperty("selectedcolor", mitk::ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite); // red
node->AddProperty("color", mitk::ColorProperty::New(1.0f, 1.0f, 0.0f), renderer, overwrite); // yellow
node->AddProperty("opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite);
node->AddProperty("show contour", mitk::BoolProperty::New(false), renderer, overwrite);
node->AddProperty("close contour", mitk::BoolProperty::New(false), renderer, overwrite);
node->AddProperty("contourcolor", mitk::ColorProperty::New(1.0f, 0.0f, 0.0f), renderer, overwrite);
node->AddProperty("contoursize", mitk::FloatProperty::New(0.5), renderer, overwrite);
node->AddProperty("show points", mitk::BoolProperty::New(true), renderer, overwrite);
node->AddProperty("updateDataOnRender", mitk::BoolProperty::New(true), renderer, overwrite);
Superclass::SetDefaultProperties(node, renderer, overwrite);
}
diff --git a/Modules/Core/src/Rendering/mitkVideoRecorder.cpp b/Modules/Core/src/Rendering/mitkVideoRecorder.cpp
index 117946b90f..064c0efd5a 100644
--- a/Modules/Core/src/Rendering/mitkVideoRecorder.cpp
+++ b/Modules/Core/src/Rendering/mitkVideoRecorder.cpp
@@ -1,391 +1,409 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
std::string mitk::VideoRecorder::GetFileExtension(OutputFormat format)
{
switch (format)
{
case OutputFormat::WebM_VP9:
return ".webm";
case OutputFormat::MP4_H264:
return ".mp4";
default:
break;
}
mitkThrow() << "Unknown output format for video recording.";
}
namespace
{
mitk::IPreferences* GetPreferences()
{
auto* preferencesService = mitk::CoreServices::GetPreferencesService();
return preferencesService->GetSystemPreferences()->Node("org.mitk.views.moviemaker");
}
class RecordingSession
{
public:
RecordingSession(vtkRenderWindow* renderWindow, mitk::VideoRecorder::OutputFormat format)
: m_FrameDir(mitk::IOUtil::CreateTemporaryDirectory("MITK_RecordingSession_XXXXXX")),
m_NumberOfFrames(0)
{
m_WindowToImageFilter->SetInput(renderWindow);
if (mitk::VideoRecorder::OutputFormat::MP4_H264 == format)
{
// H.264 only supports image dimensions that are a multiple of 2. Resize if necessary.
auto* size = renderWindow->GetActualSize();
if (size[0] & 1 || size[1] & 1)
{
m_ImageResize->SetInputConnection(m_WindowToImageFilter->GetOutputPort());
m_ImageResize->SetOutputDimensions(size[0] & ~1, size[1] & ~1, -1);
m_ImageResize->SetInterpolate(0);
m_ImageResize->BorderOn();
m_ImageWriter->SetInputConnection(m_ImageResize->GetOutputPort());
return;
}
}
m_ImageWriter->SetInputConnection(m_WindowToImageFilter->GetOutputPort());
}
~RecordingSession()
{
std::error_code errorCode;
std::filesystem::remove_all(m_FrameDir, errorCode);
}
RecordingSession(const RecordingSession&) = delete;
RecordingSession& operator=(const RecordingSession&) = delete;
std::filesystem::path GetFrameDir() const
{
return m_FrameDir;
}
void RecordFrame()
{
m_WindowToImageFilter->Modified();
std::stringstream frameFilename;
frameFilename << std::setw(6) << std::setfill('0') << m_NumberOfFrames << ".png";
const auto framePath = m_FrameDir / frameFilename.str();
m_ImageWriter->SetFileName(framePath.string().c_str());
m_ImageWriter->Write();
++m_NumberOfFrames;
}
private:
std::filesystem::path m_FrameDir;
unsigned int m_NumberOfFrames;
vtkNew m_WindowToImageFilter;
vtkNew m_ImageResize;
vtkNew m_ImageWriter;
};
}
namespace mitk
{
class VideoRecorder::Impl
{
public:
Impl()
: m_FrameRate(30)
{
}
~Impl() = default;
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
std::filesystem::path GetFFmpegPath() const
{
if (m_FFmpegPath)
return m_FFmpegPath.value();
auto* preferences = GetPreferences();
if (nullptr != preferences)
{
auto ffmpegPath = preferences->Get("ffmpeg", "");
if (!ffmpegPath.empty())
return ffmpegPath;
}
return std::filesystem::path();
}
void SetFFmpegPath(const std::filesystem::path& path)
{
m_FFmpegPath = path;
}
std::filesystem::path GetOutputPath() const
{
return m_OutputPath;
}
void SetOutputPath(const std::filesystem::path& path)
{
m_OutputPath = path;
}
mitk::VideoRecorder::OutputFormat GetOutputFormat() const
{
if (m_OutputFormat)
return m_OutputFormat.value();
auto* preferences = GetPreferences();
if (nullptr != preferences)
return static_cast(preferences->GetInt("format", 0));
return OutputFormat::WebM_VP9;
}
void SetOutputFormat(OutputFormat format)
{
m_OutputFormat = format;
}
std::string GetRenderWindowName() const
{
return m_RenderWindowName;
}
void SetRenderWindowName(const std::string& renderWindowName)
{
m_RenderWindowName = renderWindowName;
}
int GetFrameRate() const
{
return m_FrameRate;
}
void SetFrameRate(unsigned int fps)
{
m_FrameRate = fps;
}
bool OnAir() const
{
return nullptr != m_RecordingSession.get();
}
void StartRecording()
{
if (this->OnAir())
mitkThrow() << "Recording session already running.";
auto renderWindowName = this->GetRenderWindowName();
if (renderWindowName.empty())
mitkThrow() << "No render window specified for recording.";
auto* renderWindow = BaseRenderer::GetRenderWindowByName(renderWindowName);
if (nullptr == renderWindow)
mitkThrow() << "\"" << renderWindowName << "\" references unknown render window for recording.";
m_RecordingSession = std::make_unique(renderWindow, this->GetOutputFormat());
}
void RecordFrame()
{
if (!this->OnAir())
mitkThrow() << "Cannot record frame. No recording session running.";
m_RecordingSession->RecordFrame();
}
std::string GetFFmpegCommandLine() const
{
bool vp9 = OutputFormat::WebM_VP9 == this->GetOutputFormat();
std::stringstream stream;
- stream << this->GetFFmpegPath()
+ stream << this->GetFFmpegPath() << ' '
<< "-y" << ' '
<< "-r " << std::to_string(this->GetFrameRate()) << ' '
<< "-i %6d.png" << ' '
<< "-c:v " << (vp9 ? "libvpx-vp9" : "libx264") << ' '
<< "-crf " << (vp9 ? "31" : "23") << ' '
<< "-pix_fmt yuv420p" << ' '
<< "-b:v 0" << ' '
<< this->GetOutputPath();
return stream.str();
}
int ExecuteFFmpeg() const
{
auto commandLine = this->GetFFmpegCommandLine();
auto commandLineCStr = commandLine.c_str();
auto workingDirectory = m_RecordingSession->GetFrameDir().string();
auto* ffmpeg = itksysProcess_New();
itksysProcess_SetOption(ffmpeg, itksysProcess_Option_Verbatim, 1);
itksysProcess_SetCommand(ffmpeg, &commandLineCStr);
itksysProcess_SetWorkingDirectory(ffmpeg, workingDirectory.c_str());
itksysProcess_Execute(ffmpeg);
itksysProcess_WaitForExit(ffmpeg, nullptr);
- if (itksysProcess_State_Exited != itksysProcess_GetState(ffmpeg))
+ auto state = itksysProcess_GetState(ffmpeg);
+
+ if (itksysProcess_State_Exited != state)
{
+ std::stringstream message;
+ message << "FFmpeg process did not exit as expected: ";
+
+ if (itksysProcess_State_Error == state)
+ {
+ message << itksysProcess_GetErrorString(ffmpeg);
+ }
+ else if (itksysProcess_State_Exception == state)
+ {
+ message << itksysProcess_GetExceptionString(ffmpeg);
+ }
+
+ message << "\n Command: " << commandLineCStr;
+ message << "\n Working directory: " << workingDirectory.c_str();
+
itksysProcess_Delete(ffmpeg);
- mitkThrow() << "FFmpeg process did not exit as expected.";
+
+ mitkThrow() << message.str();
}
auto exitCode = itksysProcess_GetExitValue(ffmpeg);
itksysProcess_Delete(ffmpeg);
return exitCode;
}
int StopRecording()
{
if (!this->OnAir())
mitkThrow() << "No recording session running.";
if (this->GetFFmpegPath().empty())
mitkThrow() << "Path to FFmpeg not set.";
if (this->GetOutputPath().empty())
mitkThrow() << "Path to output video file not set.";
auto exitCode = this->ExecuteFFmpeg();
m_RecordingSession = nullptr;
return exitCode;
}
private:
std::optional m_FFmpegPath;
std::filesystem::path m_OutputPath;
std::optional m_OutputFormat;
std::string m_RenderWindowName;
unsigned int m_FrameRate;
std::unique_ptr m_RecordingSession;
};
}
mitk::VideoRecorder::VideoRecorder()
: m_Impl(std::make_unique())
{
}
mitk::VideoRecorder::~VideoRecorder()
{
}
std::filesystem::path mitk::VideoRecorder::GetFFmpegPath() const
{
return m_Impl->GetFFmpegPath();
}
void mitk::VideoRecorder::SetFFmpegPath(const std::filesystem::path& path)
{
m_Impl->SetFFmpegPath(path);
}
std::filesystem::path mitk::VideoRecorder::GetOutputPath() const
{
return m_Impl->GetOutputPath();
}
void mitk::VideoRecorder::SetOutputPath(const std::filesystem::path& path)
{
m_Impl->SetOutputPath(path);
}
mitk::VideoRecorder::OutputFormat mitk::VideoRecorder::GetOutputFormat() const
{
return m_Impl->GetOutputFormat();
}
void mitk::VideoRecorder::SetOutputFormat(OutputFormat format)
{
m_Impl->SetOutputFormat(format);
}
std::string mitk::VideoRecorder::GetRenderWindowName() const
{
return m_Impl->GetRenderWindowName();
}
void mitk::VideoRecorder::SetRenderWindowName(const std::string& renderWindowName)
{
m_Impl->SetRenderWindowName(renderWindowName);
}
int mitk::VideoRecorder::GetFrameRate() const
{
return m_Impl->GetFrameRate();
}
void mitk::VideoRecorder::SetFrameRate(unsigned int fps)
{
m_Impl->SetFrameRate(fps);
}
void mitk::VideoRecorder::StartRecording()
{
m_Impl->StartRecording();
}
void mitk::VideoRecorder::RecordFrame() const
{
m_Impl->RecordFrame();
}
int mitk::VideoRecorder::StopRecording()
{
return m_Impl->StopRecording();
}
diff --git a/Modules/Multilabel/mitkLabelSetImage.cpp b/Modules/Multilabel/mitkLabelSetImage.cpp
index 5dabaf8adb..48cfd421c1 100644
--- a/Modules/Multilabel/mitkLabelSetImage.cpp
+++ b/Modules/Multilabel/mitkLabelSetImage.cpp
@@ -1,1553 +1,1562 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkLabelSetImage.h"
#include "mitkImageAccessByItk.h"
#include "mitkImageCast.h"
#include "mitkImagePixelReadAccessor.h"
#include "mitkImagePixelWriteAccessor.h"
#include "mitkInteractionConst.h"
#include "mitkLookupTableProperty.h"
#include "mitkPadImageFilter.h"
#include "mitkRenderingManager.h"
#include "mitkDICOMSegmentationPropertyHelper.h"
#include "mitkDICOMQIPropertyHelper.h"
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
template
void SetToZero(itk::Image *source)
{
source->FillBuffer(0);
}
template
void CreateLabelMaskProcessing(mitk::Image *layerImage, mitk::Image *mask, mitk::LabelSet::PixelType index)
{
mitk::ImagePixelReadAccessor readAccessor(layerImage);
mitk::ImagePixelWriteAccessor writeAccessor(mask);
std::size_t numberOfPixels = 1;
for (int dim = 0; dim < static_cast(VImageDimension); ++dim)
numberOfPixels *= static_cast(readAccessor.GetDimension(dim));
auto src = readAccessor.GetData();
auto dest = writeAccessor.GetData();
for (std::size_t i = 0; i < numberOfPixels; ++i)
{
if (index == *(src + i))
*(dest + i) = 1;
}
}
mitk::LabelSetImage::LabelSetImage()
: mitk::Image(), m_UnlabeledLabelLock(false), m_ActiveLayer(0), m_activeLayerInvalid(false)
{
// Add some DICOM Tags as properties to segmentation image
DICOMSegmentationPropertyHelper::DeriveDICOMSegmentationProperties(this);
}
mitk::LabelSetImage::LabelSetImage(const mitk::LabelSetImage &other)
: Image(other),
m_UnlabeledLabelLock(other.m_UnlabeledLabelLock),
m_ActiveLayer(other.GetActiveLayer()),
m_activeLayerInvalid(false)
{
for (unsigned int i = 0; i < other.GetNumberOfLayers(); i++)
{
// Clone LabelSet data
mitk::LabelSet::Pointer lsClone = other.GetLabelSet(i)->Clone();
this->RegisterLabelSet(lsClone);
m_LabelSetContainer.push_back(lsClone);
// clone layer Image data
mitk::Image::Pointer liClone = other.GetLayerImage(i)->Clone();
m_LayerContainer.push_back(liClone);
}
+ this->ReinitMaps();
+
// Add some DICOM Tags as properties to segmentation image
DICOMSegmentationPropertyHelper::DeriveDICOMSegmentationProperties(this);
}
void mitk::LabelSetImage::OnLabelSetModified()
{
Superclass::Modified();
}
void mitk::LabelSetImage::Initialize(const mitk::Image *other)
{
mitk::PixelType pixelType(mitk::MakeScalarPixelType());
if (other->GetDimension() == 2)
{
const unsigned int dimensions[] = {other->GetDimension(0), other->GetDimension(1), 1};
Superclass::Initialize(pixelType, 3, dimensions);
}
else
{
Superclass::Initialize(pixelType, other->GetDimension(), other->GetDimensions());
}
auto originalGeometry = other->GetTimeGeometry()->Clone();
this->SetTimeGeometry(originalGeometry);
// initialize image memory to zero
if (4 == this->GetDimension())
{
AccessFixedDimensionByItk(this, SetToZero, 4);
}
else
{
AccessByItk(this, SetToZero);
}
// Transfer some general DICOM properties from the source image to derived image (e.g. Patient information,...)
DICOMQIPropertyHelper::DeriveDICOMSourceProperties(other, this);
// Add a inital LabelSet ans corresponding image data to the stack
if (this->GetNumberOfLayers() == 0)
{
AddLayer();
}
}
mitk::LabelSetImage::~LabelSetImage()
{
for (auto ls : m_LabelSetContainer)
{
this->ReleaseLabelSet(ls);
}
m_LabelSetContainer.clear();
}
mitk::Image *mitk::LabelSetImage::GetLayerImage(unsigned int layer)
{
return m_LayerContainer[layer];
}
const mitk::Image *mitk::LabelSetImage::GetLayerImage(unsigned int layer) const
{
return m_LayerContainer[layer];
}
unsigned int mitk::LabelSetImage::GetActiveLayer() const
{
return m_ActiveLayer;
}
unsigned int mitk::LabelSetImage::GetNumberOfLayers() const
{
return m_LabelSetContainer.size();
}
void mitk::LabelSetImage::RegisterLabelSet(mitk::LabelSet* ls)
{
// add modified event listener to LabelSet (listen to LabelSet changes)
itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New();
command->SetCallbackFunction(this, &mitk::LabelSetImage::OnLabelSetModified);
ls->AddObserver(itk::ModifiedEvent(), command);
ls->AddLabelEvent.AddListener(mitk::MessageDelegate1(
this, &LabelSetImage::OnLabelAdded));
ls->ModifyLabelEvent.AddListener(mitk::MessageDelegate1(
this, &LabelSetImage::OnLabelModified));
ls->RemoveLabelEvent.AddListener(mitk::MessageDelegate1(
this, &LabelSetImage::OnLabelRemoved));
ls->m_ReservedLabelValuesFunctor = [this]() {return this->GetUsedLabelValues(); };
}
void mitk::LabelSetImage::ReleaseLabelSet(mitk::LabelSet* ls)
{
ls->RemoveAllObservers();
ls->AddLabelEvent.RemoveListener(mitk::MessageDelegate1(
this, &LabelSetImage::OnLabelAdded));
ls->ModifyLabelEvent.RemoveListener(mitk::MessageDelegate1(
this, &LabelSetImage::OnLabelModified));
ls->RemoveLabelEvent.RemoveListener(mitk::MessageDelegate1(
this, &LabelSetImage::OnLabelRemoved));
ls->m_ReservedLabelValuesFunctor = nullptr;
}
void mitk::LabelSetImage::RemoveLayer()
{
int layerToDelete = GetActiveLayer();
// remove all observers from active label set
GetLabelSet(layerToDelete)->RemoveAllObservers();
// set the active layer to one below, if exists.
if (layerToDelete != 0)
{
SetActiveLayer(layerToDelete - 1);
}
else
{
// we are deleting layer zero, it should not be copied back into the vector
m_activeLayerInvalid = true;
}
// remove labelset and image data
m_LabelSetContainer.erase(m_LabelSetContainer.begin() + layerToDelete);
m_LayerContainer.erase(m_LayerContainer.begin() + layerToDelete);
if (layerToDelete == 0)
{
this->SetActiveLayer(layerToDelete);
}
this->OnGroupRemoved(layerToDelete);
this->Modified();
}
void mitk::LabelSetImage::RemoveGroup(GroupIndexType indexToDelete)
{
const auto activeIndex = GetActiveLayer();
// remove all observers from active label set
GetLabelSet(indexToDelete)->RemoveAllObservers();
// set the active layer to one below, if exists.
if (activeIndex>indexToDelete)
{
SetActiveLayer(activeIndex - 1);
}
else if (activeIndex==indexToDelete)
{
// we are deleting layer zero, it should not be copied back into the vector
m_activeLayerInvalid = true;
}
// remove labelset and image data
m_LabelSetContainer.erase(m_LabelSetContainer.begin() + indexToDelete);
m_LayerContainer.erase(m_LayerContainer.begin() + indexToDelete);
if (indexToDelete == activeIndex)
{ //enforces the new active layer to be set and copied
auto newActiveIndex = indexToDelete < GetNumberOfLayers() ? indexToDelete : GetNumberOfLayers() - 1;
this->SetActiveLayer(newActiveIndex);
}
this->OnGroupRemoved(indexToDelete);
this->Modified();
}
mitk::LabelSetImage::LabelValueVectorType mitk::LabelSetImage::GetUsedLabelValues() const
{
LabelValueVectorType result = { UnlabeledValue };
for (auto [value, label] : m_LabelMap)
{
result.emplace_back(value);
}
return result;
}
unsigned int mitk::LabelSetImage::AddLayer(mitk::LabelSet::Pointer labelSet)
{
mitk::Image::Pointer newImage = mitk::Image::New();
newImage->Initialize(this->GetPixelType(),
this->GetDimension(),
this->GetDimensions(),
this->GetImageDescriptor()->GetNumberOfChannels());
newImage->SetTimeGeometry(this->GetTimeGeometry()->Clone());
if (newImage->GetDimension() < 4)
{
AccessByItk(newImage, SetToZero);
}
else
{
AccessFixedDimensionByItk(newImage, SetToZero, 4);
}
return this->AddLayer(newImage, labelSet);
}
unsigned int mitk::LabelSetImage::AddLayer(mitk::Image::Pointer layerImage, mitk::LabelSet::Pointer labelSet)
{
unsigned int newLabelSetId = m_LayerContainer.size();
// Add labelset to layer
mitk::LabelSet::Pointer ls;
if (labelSet.IsNotNull())
{
ls = labelSet;
}
else
{
ls = mitk::LabelSet::New();
ls->SetActiveLabel(UnlabeledValue);
}
ls->SetLayer(newLabelSetId);
// push a new working image for the new layer
m_LayerContainer.push_back(layerImage);
// push a new labelset for the new layer
m_LabelSetContainer.push_back(ls);
RegisterLabelSet(ls);
this->ReinitMaps();
SetActiveLayer(newLabelSetId);
this->Modified();
this->OnGroupAdded(newLabelSetId);
return newLabelSetId;
}
void mitk::LabelSetImage::AddLabelSetToLayer(const unsigned int layerIdx, const mitk::LabelSet* labelSet)
{
if (m_LayerContainer.size() <= layerIdx)
{
mitkThrow() << "Trying to add labelSet to non-existing layer.";
}
auto clonedLabelSet = labelSet->Clone();
this->RegisterLabelSet(clonedLabelSet);
std::vector addedGroups;
if (layerIdx < m_LabelSetContainer.size())
{
if (m_LabelSetContainer[layerIdx].IsNotNull())
{
this->ReleaseLabelSet(m_LabelSetContainer[layerIdx]);
}
m_LabelSetContainer[layerIdx] = clonedLabelSet;
}
else
{
while (layerIdx >= m_LabelSetContainer.size())
{
mitk::LabelSet::Pointer defaultLabelSet = mitk::LabelSet::New();
defaultLabelSet->SetActiveLabel(UnlabeledValue);
defaultLabelSet->SetLayer(m_LabelSetContainer.size());
this->RegisterLabelSet(defaultLabelSet);
this->ReinitMaps();
m_LabelSetContainer.push_back(defaultLabelSet);
addedGroups.emplace_back(m_LabelSetContainer.size() - 1);
}
m_LabelSetContainer.push_back(clonedLabelSet);
addedGroups.emplace_back(m_LabelSetContainer.size() - 1);
}
this->ReinitMaps();
for (auto groupID : addedGroups)
{
this->m_GroupAddedMessage.Send(groupID);
}
}
void mitk::LabelSetImage::SetActiveLayer(unsigned int layer)
{
try
{
if (4 == this->GetDimension())
{
if ((layer != GetActiveLayer() || m_activeLayerInvalid) && (layer < this->GetNumberOfLayers()))
{
BeforeChangeLayerEvent.Send();
if (m_activeLayerInvalid)
{
// We should not write the invalid layer back to the vector
m_activeLayerInvalid = false;
}
else
{
AccessFixedDimensionByItk_n(this, ImageToLayerContainerProcessing, 4, (GetActiveLayer()));
}
m_ActiveLayer = layer; // only at this place m_ActiveLayer should be manipulated!!! Use Getter and Setter
AccessFixedDimensionByItk_n(this, LayerContainerToImageProcessing, 4, (GetActiveLayer()));
AfterChangeLayerEvent.Send();
}
}
else
{
if ((layer != GetActiveLayer() || m_activeLayerInvalid) && (layer < this->GetNumberOfLayers()))
{
BeforeChangeLayerEvent.Send();
if (m_activeLayerInvalid)
{
// We should not write the invalid layer back to the vector
m_activeLayerInvalid = false;
}
else
{
AccessByItk_1(this, ImageToLayerContainerProcessing, GetActiveLayer());
}
m_ActiveLayer = layer; // only at this place m_ActiveLayer should be manipulated!!! Use Getter and Setter
AccessByItk_1(this, LayerContainerToImageProcessing, GetActiveLayer());
AfterChangeLayerEvent.Send();
}
}
}
catch (itk::ExceptionObject &e)
{
mitkThrow() << e.GetDescription();
}
this->Modified();
}
void mitk::LabelSetImage::ClearBuffer()
{
try
{
if (this->GetDimension() == 4)
{ //remark: this extra branch was added, because LabelSetImage instances can be
//dynamic (4D), but AccessByItk by support only supports 2D and 3D.
//The option to change the CMake default dimensions for AccessByItk was
//dropped (for details see discussion in T28756)
AccessFixedDimensionByItk(this, ClearBufferProcessing,4);
}
else
{
AccessByItk(this, ClearBufferProcessing);
}
this->Modified();
}
catch (itk::ExceptionObject &e)
{
mitkThrow() << e.GetDescription();
}
}
bool mitk::LabelSetImage::ExistLabel(PixelType pixelValue) const
{
bool exist = false;
for (unsigned int lidx = 0; lidx < GetNumberOfLayers(); lidx++)
exist |= m_LabelSetContainer[lidx]->ExistLabel(pixelValue);
return exist;
}
bool mitk::LabelSetImage::ExistLabel(PixelType pixelValue, unsigned int layer) const
{
bool exist = m_LabelSetContainer[layer]->ExistLabel(pixelValue);
return exist;
}
bool mitk::LabelSetImage::ExistLabelSet(unsigned int layer) const
{
return layer < m_LabelSetContainer.size();
}
void mitk::LabelSetImage::MergeLabel(PixelType pixelValue, PixelType sourcePixelValue, unsigned int layer)
{
try
{
AccessByItk_2(this, MergeLabelProcessing, pixelValue, sourcePixelValue);
}
catch (itk::ExceptionObject &e)
{
mitkThrow() << e.GetDescription();
}
GetLabelSet(layer)->SetActiveLabel(pixelValue);
this->m_LabelModifiedMessage.Send(sourcePixelValue);
this->m_LabelModifiedMessage.Send(pixelValue);
this->m_LabelsChangedMessage.Send({ sourcePixelValue, pixelValue });
Modified();
}
void mitk::LabelSetImage::MergeLabels(PixelType pixelValue, const std::vector& vectorOfSourcePixelValues, unsigned int layer)
{
try
{
for (unsigned int idx = 0; idx < vectorOfSourcePixelValues.size(); idx++)
{
AccessByItk_2(this, MergeLabelProcessing, pixelValue, vectorOfSourcePixelValues[idx]);
this->m_LabelModifiedMessage.Send(vectorOfSourcePixelValues[idx]);
}
}
catch (itk::ExceptionObject &e)
{
mitkThrow() << e.GetDescription();
}
GetLabelSet(layer)->SetActiveLabel(pixelValue);
this->m_LabelModifiedMessage.Send(pixelValue);
auto modifiedValues = vectorOfSourcePixelValues;
modifiedValues.push_back(pixelValue);
this->m_LabelsChangedMessage.Send(modifiedValues);
Modified();
}
void mitk::LabelSetImage::RemoveLabel(LabelValueType pixelValue)
{
auto groupID = this->GetGroupIndexOfLabel(pixelValue);
//first erase the pixel content (also triggers a LabelModified event)
this->EraseLabel(pixelValue);
//now remove the label entry itself
this->GetLabelSet(groupID)->RemoveLabel(pixelValue);
// in the interim version triggered by label set events: this->m_LabelRemovedMessage.Send(pixelValue);
this->m_LabelsChangedMessage.Send({ pixelValue });
this->m_GroupModifiedMessage.Send(groupID);
}
void mitk::LabelSetImage::RemoveLabels(const std::vector& VectorOfLabelPixelValues)
{
for (unsigned int idx = 0; idx < VectorOfLabelPixelValues.size(); idx++)
{
this->RemoveLabel(VectorOfLabelPixelValues[idx]);
this->m_LabelsChangedMessage.Send({ VectorOfLabelPixelValues[idx] });
}
}
void mitk::LabelSetImage::EraseLabel(PixelType pixelValue)
{
try
{
auto groupID = this->GetGroupIndexOfLabel(pixelValue);
mitk::Image* groupImage = this->GetActiveLayer() != groupID
? this->GetLayerImage(groupID)
: this;
if (4 == this->GetDimension())
{
AccessFixedDimensionByItk_1(groupImage, EraseLabelProcessing, 4, pixelValue);
}
else
{
AccessByItk_1(groupImage, EraseLabelProcessing, pixelValue);
}
}
catch (const itk::ExceptionObject& e)
{
mitkThrow() << e.GetDescription();
}
this->m_LabelModifiedMessage.Send(pixelValue);
this->m_LabelsChangedMessage.Send({ pixelValue });
Modified();
}
void mitk::LabelSetImage::EraseLabels(const std::vector& VectorOfLabelPixelValues)
{
for (unsigned int idx = 0; idx < VectorOfLabelPixelValues.size(); idx++)
{
this->EraseLabel(VectorOfLabelPixelValues[idx]);
}
}
mitk::Label *mitk::LabelSetImage::GetActiveLabel(unsigned int layer)
{
if (m_LabelSetContainer.size() <= layer)
return nullptr;
else
return m_LabelSetContainer[layer]->GetActiveLabel();
}
const mitk::Label* mitk::LabelSetImage::GetActiveLabel(unsigned int layer) const
{
if (m_LabelSetContainer.size() <= layer)
return nullptr;
else
return m_LabelSetContainer[layer]->GetActiveLabel();
}
mitk::Label *mitk::LabelSetImage::GetLabel(PixelType pixelValue, unsigned int layer) const
{
if (m_LabelSetContainer.size() <= layer)
return nullptr;
else
return m_LabelSetContainer[layer]->GetLabel(pixelValue);
}
mitk::LabelSet *mitk::LabelSetImage::GetLabelSet(unsigned int layer)
{
if (m_LabelSetContainer.size() <= layer)
return nullptr;
else
return m_LabelSetContainer[layer].GetPointer();
}
const mitk::LabelSet *mitk::LabelSetImage::GetLabelSet(unsigned int layer) const
{
if (m_LabelSetContainer.size() <= layer)
return nullptr;
else
return m_LabelSetContainer[layer].GetPointer();
}
mitk::LabelSet *mitk::LabelSetImage::GetActiveLabelSet()
{
if (m_LabelSetContainer.size() == 0)
return nullptr;
else
return m_LabelSetContainer[GetActiveLayer()].GetPointer();
}
const mitk::LabelSet* mitk::LabelSetImage::GetActiveLabelSet() const
{
if (m_LabelSetContainer.size() == 0)
return nullptr;
else
return m_LabelSetContainer[GetActiveLayer()].GetPointer();
}
void mitk::LabelSetImage::UpdateCenterOfMass(PixelType pixelValue)
{
this->UpdateCenterOfMass(pixelValue, this->GetGroupIndexOfLabel(pixelValue));
}
void mitk::LabelSetImage::UpdateCenterOfMass(PixelType pixelValue, unsigned int layer)
{
if (4 == this->GetDimension())
{
AccessFixedDimensionByItk_2(this, CalculateCenterOfMassProcessing, 4, pixelValue, layer);
}
else
{
AccessByItk_2(this, CalculateCenterOfMassProcessing, pixelValue, layer);
}
}
unsigned int mitk::LabelSetImage::GetNumberOfLabels(unsigned int layer) const
{
return m_LabelSetContainer[layer]->GetNumberOfLabels();
}
unsigned int mitk::LabelSetImage::GetTotalNumberOfLabels() const
{
unsigned int totalLabels(0);
auto layerIter = m_LabelSetContainer.begin();
for (; layerIter != m_LabelSetContainer.end(); ++layerIter)
totalLabels += (*layerIter)->GetNumberOfLabels();
return totalLabels;
}
void mitk::LabelSetImage::MaskStamp(mitk::Image *mask, bool forceOverwrite)
{
try
{
mitk::PadImageFilter::Pointer padImageFilter = mitk::PadImageFilter::New();
padImageFilter->SetInput(0, mask);
padImageFilter->SetInput(1, this);
padImageFilter->SetPadConstant(0);
padImageFilter->SetBinaryFilter(false);
padImageFilter->SetLowerThreshold(0);
padImageFilter->SetUpperThreshold(1);
padImageFilter->Update();
mitk::Image::Pointer paddedMask = padImageFilter->GetOutput();
if (paddedMask.IsNull())
return;
AccessByItk_2(this, MaskStampProcessing, paddedMask, forceOverwrite);
}
catch (...)
{
mitkThrow() << "Could not stamp the provided mask on the selected label.";
}
}
mitk::Image::Pointer mitk::LabelSetImage::CreateLabelMask(PixelType index, bool useActiveLayer, unsigned int layer)
{
auto previousActiveLayer = this->GetActiveLayer();
auto mask = mitk::Image::New();
try
{
// mask->Initialize(this) does not work here if this label set image has a single slice,
// since the mask would be automatically flattened to a 2-d image, whereas we expect the
// original dimension of this label set image. Hence, initialize the mask more explicitly:
mask->Initialize(this->GetPixelType(), this->GetDimension(), this->GetDimensions());
mask->SetTimeGeometry(this->GetTimeGeometry()->Clone());
auto byteSize = sizeof(LabelSetImage::PixelType);
for (unsigned int dim = 0; dim < mask->GetDimension(); ++dim)
byteSize *= mask->GetDimension(dim);
{
ImageWriteAccessor accessor(mask);
memset(accessor.GetData(), 0, byteSize);
}
if (!useActiveLayer)
this->SetActiveLayer(layer);
if (4 == this->GetDimension())
{
::CreateLabelMaskProcessing<4>(this, mask, index);
}
else if (3 == this->GetDimension())
{
::CreateLabelMaskProcessing(this, mask, index);
}
else
{
mitkThrow();
}
}
catch (...)
{
if (!useActiveLayer)
this->SetActiveLayer(previousActiveLayer);
mitkThrow() << "Could not create a mask out of the selected label.";
}
if (!useActiveLayer)
this->SetActiveLayer(previousActiveLayer);
return mask;
}
void mitk::LabelSetImage::InitializeByLabeledImage(mitk::Image::Pointer image)
{
if (image.IsNull() || image->IsEmpty() || !image->IsInitialized())
mitkThrow() << "Invalid labeled image.";
try
{
this->Initialize(image);
unsigned int byteSize = sizeof(LabelSetImage::PixelType);
for (unsigned int dim = 0; dim < image->GetDimension(); ++dim)
{
byteSize *= image->GetDimension(dim);
}
mitk::ImageWriteAccessor *accessor = new mitk::ImageWriteAccessor(static_cast(this));
memset(accessor->GetData(), 0, byteSize);
delete accessor;
auto geometry = image->GetTimeGeometry()->Clone();
this->SetTimeGeometry(geometry);
if (image->GetDimension() == 3)
{
AccessTwoImagesFixedDimensionByItk(this, image, InitializeByLabeledImageProcessing, 3);
}
else if (image->GetDimension() == 4)
{
AccessTwoImagesFixedDimensionByItk(this, image, InitializeByLabeledImageProcessing, 4);
}
else
{
mitkThrow() << image->GetDimension() << "-dimensional label set images not yet supported";
}
}
catch (...)
{
mitkThrow() << "Could not intialize by provided labeled image.";
}
this->Modified();
}
template
void mitk::LabelSetImage::InitializeByLabeledImageProcessing(LabelSetImageType *labelSetImage, ImageType *image)
{
typedef itk::ImageRegionConstIteratorWithIndex SourceIteratorType;
typedef itk::ImageRegionIterator TargetIteratorType;
TargetIteratorType targetIter(labelSetImage, labelSetImage->GetRequestedRegion());
targetIter.GoToBegin();
SourceIteratorType sourceIter(image, image->GetRequestedRegion());
sourceIter.GoToBegin();
while (!sourceIter.IsAtEnd())
{
auto sourceValue = static_cast(sourceIter.Get());
targetIter.Set(sourceValue);
if (LabelSetImage::UnlabeledValue!=sourceValue && !this->ExistLabel(sourceValue))
{
std::stringstream name;
name << "object-" << sourceValue;
double rgba[4];
m_LabelSetContainer[this->GetActiveLayer()]->GetLookupTable()->GetTableValue(sourceValue, rgba);
mitk::Color color;
color.SetRed(rgba[0]);
color.SetGreen(rgba[1]);
color.SetBlue(rgba[2]);
auto label = mitk::Label::New();
label->SetName(name.str().c_str());
label->SetColor(color);
label->SetOpacity(rgba[3]);
label->SetValue(sourceValue);
this->GetLabelSet()->AddLabel(label);
if (GetActiveLabelSet()->GetNumberOfLabels() >= mitk::Label::MAX_LABEL_VALUE ||
sourceValue >= mitk::Label::MAX_LABEL_VALUE)
this->AddLayer();
}
++sourceIter;
++targetIter;
}
}
template
void mitk::LabelSetImage::MaskStampProcessing(ImageType *itkImage, mitk::Image *mask, bool forceOverwrite)
{
typename ImageType::Pointer itkMask;
mitk::CastToItkImage(mask, itkMask);
typedef itk::ImageRegionConstIterator SourceIteratorType;
typedef itk::ImageRegionIterator TargetIteratorType;
SourceIteratorType sourceIter(itkMask, itkMask->GetLargestPossibleRegion());
sourceIter.GoToBegin();
TargetIteratorType targetIter(itkImage, itkImage->GetLargestPossibleRegion());
targetIter.GoToBegin();
int activeLabel = this->GetActiveLabel(GetActiveLayer())->GetValue();
while (!sourceIter.IsAtEnd())
{
PixelType sourceValue = sourceIter.Get();
PixelType targetValue = targetIter.Get();
if ((sourceValue != UnlabeledValue) &&
(forceOverwrite || !this->IsLabelLocked(targetValue))) // skip unlabeled pixels and locked labels
{
targetIter.Set(activeLabel);
}
++sourceIter;
++targetIter;
}
this->Modified();
}
template
void mitk::LabelSetImage::CalculateCenterOfMassProcessing(ImageType *itkImage, PixelType pixelValue, unsigned int layer)
{
if (ImageType::GetImageDimension() != 3)
{
return;
}
auto labelGeometryFilter = itk::LabelGeometryImageFilter::New();
labelGeometryFilter->SetInput(itkImage);
labelGeometryFilter->Update();
auto centroid = labelGeometryFilter->GetCentroid(pixelValue);
mitk::Point3D pos;
pos[0] = centroid[0];
pos[1] = centroid[1];
pos[2] = centroid[2];
GetLabelSet(layer)->GetLabel(pixelValue)->SetCenterOfMassIndex(pos);
this->GetSlicedGeometry()->IndexToWorld(pos, pos); // TODO: TimeGeometry?
GetLabelSet(layer)->GetLabel(pixelValue)->SetCenterOfMassCoordinates(pos);
}
template
void mitk::LabelSetImage::ClearBufferProcessing(ImageType *itkImage)
{
itkImage->FillBuffer(0);
}
template
void mitk::LabelSetImage::LayerContainerToImageProcessing(itk::Image *target,
unsigned int layer)
{
typedef itk::Image ImageType;
typename ImageType::Pointer itkSource;
// mitk::CastToItkImage(m_LayerContainer[layer], itkSource);
itkSource = ImageToItkImage(m_LayerContainer[layer]);
typedef itk::ImageRegionConstIterator SourceIteratorType;
typedef itk::ImageRegionIterator TargetIteratorType;
SourceIteratorType sourceIter(itkSource, itkSource->GetLargestPossibleRegion());
sourceIter.GoToBegin();
TargetIteratorType targetIter(target, target->GetLargestPossibleRegion());
targetIter.GoToBegin();
while (!sourceIter.IsAtEnd())
{
targetIter.Set(sourceIter.Get());
++sourceIter;
++targetIter;
}
}
template
void mitk::LabelSetImage::ImageToLayerContainerProcessing(itk::Image *source,
unsigned int layer) const
{
typedef itk::Image ImageType;
typename ImageType::Pointer itkTarget;
// mitk::CastToItkImage(m_LayerContainer[layer], itkTarget);
itkTarget = ImageToItkImage(m_LayerContainer[layer]);
typedef itk::ImageRegionConstIterator SourceIteratorType;
typedef itk::ImageRegionIterator TargetIteratorType;
SourceIteratorType sourceIter(source, source->GetLargestPossibleRegion());
sourceIter.GoToBegin();
TargetIteratorType targetIter(itkTarget, itkTarget->GetLargestPossibleRegion());
targetIter.GoToBegin();
while (!sourceIter.IsAtEnd())
{
targetIter.Set(sourceIter.Get());
++sourceIter;
++targetIter;
}
}
template
void mitk::LabelSetImage::EraseLabelProcessing(ImageType *itkImage, PixelType pixelValue)
{
typedef itk::ImageRegionIterator IteratorType;
IteratorType iter(itkImage, itkImage->GetLargestPossibleRegion());
iter.GoToBegin();
while (!iter.IsAtEnd())
{
PixelType value = iter.Get();
if (value == pixelValue)
{
iter.Set(0);
}
++iter;
}
}
template
void mitk::LabelSetImage::MergeLabelProcessing(ImageType *itkImage, PixelType pixelValue, PixelType index)
{
typedef itk::ImageRegionIterator IteratorType;
IteratorType iter(itkImage, itkImage->GetLargestPossibleRegion());
iter.GoToBegin();
while (!iter.IsAtEnd())
{
if (iter.Get() == index)
{
iter.Set(pixelValue);
}
++iter;
}
}
void mitk::LabelSetImage::OnLabelAdded(LabelValueType labelValue)
{
Label* label = nullptr;
unsigned int layerID = 0;
for (; layerID < this->GetNumberOfLayers(); ++layerID)
{
label = this->GetLabel(labelValue, layerID);
if (nullptr != label) break;
}
if (!label) mitkThrow() << "Wrong internal state. OnLabelAdded was triggered, but label cannot be found. Invalid label: " << labelValue;
AddLabelToMap(labelValue, label, layerID);
this->m_LabelAddedMessage.Send(labelValue);
}
void mitk::LabelSetImage::AddLabelToMap(LabelValueType labelValue, mitk::Label* label, GroupIndexType groupID)
{
if (m_LabelMap.find(labelValue)!=m_LabelMap.end())
mitkThrow() << "Segmentation is in an invalid state: Label value collision. A label was added with a LabelValue already in use. LabelValue: " << labelValue;
m_LabelMap[labelValue] = label;
m_LabelToGroupMap[labelValue] = groupID;
auto groupFinding = m_GroupToLabelMap.find(groupID);
if (groupFinding == m_GroupToLabelMap.end())
{
m_GroupToLabelMap[groupID] = { labelValue };
}
else
{
m_GroupToLabelMap[groupID].push_back(labelValue);
}
}
void mitk::LabelSetImage::OnLabelModified(LabelValueType labelValue)
{
this->m_LabelModifiedMessage.Send(labelValue);
}
void mitk::LabelSetImage::OnLabelRemoved(LabelValueType labelValue)
{
m_LabelMap.erase(labelValue);
auto finding = m_LabelToGroupMap.find(labelValue);
if (finding != m_LabelToGroupMap.end())
{
auto labelsInGroup = m_GroupToLabelMap[finding->second];
auto labelFinding = std::find(labelsInGroup.begin(), labelsInGroup.end(),finding->second);
if (labelFinding != labelsInGroup.end())
{
labelsInGroup.erase(labelFinding);
}
m_LabelToGroupMap.erase(labelValue);
}
this->m_LabelRemovedMessage.Send(labelValue);
}
void mitk::LabelSetImage::OnGroupAdded(GroupIndexType groupIndex)
{
this->m_GroupToLabelMap.insert(std::make_pair(groupIndex, LabelValueVectorType()));
this->m_GroupAddedMessage.Send(groupIndex);
}
void mitk::LabelSetImage::OnGroupModified(GroupIndexType groupIndex)
{
this->m_GroupModifiedMessage.Send(groupIndex);
}
void mitk::LabelSetImage::OnGroupRemoved(GroupIndexType groupIndex)
{
this->ReinitMaps();
this->m_GroupRemovedMessage.Send(groupIndex);
}
// future implementation for T28524
//bool mitk::LabelSetImage::ExistLabel(LabelValueType value, GroupIndexType groupIndex) const
//{
// auto finding = m_LabelToGroupMap.find(value);
// if (m_LabelToGroupMap.end() != finding)
// {
// return finding->second == groupIndex;
// }
// return false;
//}
//
//bool mitk::LabelSetImage::ExistGroup(GroupIndexType index) const
//{
// return index < m_LabelSetContainer.size();
//}
bool mitk::LabelSetImage::ExistGroup(GroupIndexType index) const
{
return index < m_LabelSetContainer.size();
}
bool mitk::LabelSetImage::IsLabelInGroup(LabelValueType value) const
{
GroupIndexType dummy;
return this->IsLabelInGroup(value, dummy);
}
bool mitk::LabelSetImage::IsLabelInGroup(LabelValueType value, GroupIndexType& groupIndex) const
{
auto finding = m_LabelToGroupMap.find(value);
if (m_LabelToGroupMap.end() != finding)
{
groupIndex = finding->second;
return true;
}
return false;
}
mitk::LabelSetImage::GroupIndexType mitk::LabelSetImage::GetGroupIndexOfLabel(LabelValueType value) const
{
auto finding = m_LabelToGroupMap.find(value);
if (m_LabelToGroupMap.end() == finding)
{
mitkThrow()<< "Cannot deduce group index. Passed label value does not exist. Value: "<< value;
}
return finding->second;
}
const mitk::Label* mitk::LabelSetImage::GetLabel(LabelValueType value) const
{
auto finding = m_LabelMap.find(value);
if (m_LabelMap.end() != finding)
{
return finding->second;
}
return nullptr;
};
mitk::Label* mitk::LabelSetImage::GetLabel(LabelValueType value)
{
auto finding = m_LabelMap.find(value);
if (m_LabelMap.end() != finding)
{
return finding->second;
}
return nullptr;
};
bool mitk::LabelSetImage::IsLabelLocked(LabelValueType value) const
{
if (value == UnlabeledValue)
{
return m_UnlabeledLabelLock;
}
const auto label = this->GetLabel(value);
return label->GetLocked();
}
const mitk::LabelSetImage::ConstLabelVectorType mitk::LabelSetImage::GetLabels() const
{
ConstLabelVectorType result;
for (auto [value, label] : m_LabelMap)
{
result.emplace_back(label);
}
return result;
}
const mitk::LabelSetImage::LabelVectorType mitk::LabelSetImage::GetLabels()
{
LabelVectorType result;
for (auto [value, label] : m_LabelMap)
{
result.emplace_back(label);
}
return result;
}
const mitk::LabelSetImage::ConstLabelVectorType mitk::LabelSetImage::GetLabelsInGroup(GroupIndexType index) const
{
if (!this->ExistGroup(index))
- {
mitkThrow() << "Cannot get labels of an invalid group. Invalid group index: " << index;
- }
mitk::LabelSetImage::ConstLabelVectorType result;
+ const auto labelValues = m_GroupToLabelMap.find(index)->second;
- const auto labellist = m_GroupToLabelMap.find(index)->second;
- for (const auto& labelvalue : labellist)
+ for (const auto& labelValue : labelValues)
{
- result.emplace_back(this->GetLabel(labelvalue));
+ const auto* label = this->GetLabel(labelValue);
+
+ if (label != nullptr)
+ result.emplace_back(label);
}
return result;
}
const mitk::LabelSetImage::LabelVectorType mitk::LabelSetImage::GetLabelsInGroup(GroupIndexType index)
{
if (!this->ExistGroup(index))
- {
mitkThrow() << "Cannot get labels of an invalid group. Invalid group index: " << index;
- }
mitk::LabelSetImage::LabelVectorType result;
+ const auto labelValues = m_GroupToLabelMap[index];
- const auto labellist = m_GroupToLabelMap[index];
- for (const auto& labelvalue : labellist)
+ for (const auto& labelValue : labelValues)
{
- result.emplace_back(this->GetLabel(labelvalue));
+ auto* label = this->GetLabel(labelValue);
+
+ if (label != nullptr)
+ result.emplace_back(label);
}
return result;
}
void mitk::LabelSetImage::ReinitMaps()
{
this->m_LabelMap.clear();
this->m_LabelToGroupMap.clear();
this->m_GroupToLabelMap.clear();
for (GroupIndexType layerID = 0; layerID < this->GetNumberOfLayers(); ++layerID)
{
auto labelSet = this->GetLabelSet(layerID);
- for (auto iter = labelSet->IteratorBegin(); iter != labelSet->IteratorEnd(); ++iter)
+
+ if (labelSet->GetNumberOfLabels() != 0)
{
- if (iter->first != UnlabeledValue)
+ for (auto iter = labelSet->IteratorBegin(); iter != labelSet->IteratorEnd(); ++iter)
{
- this->AddLabelToMap(iter->first, iter->second, layerID);
+ if (iter->first != UnlabeledValue)
+ this->AddLabelToMap(iter->first, iter->second, layerID);
}
}
+ else
+ {
+ m_GroupToLabelMap[layerID] = {};
+ }
}
}
-
bool mitk::Equal(const mitk::LabelSetImage &leftHandSide,
const mitk::LabelSetImage &rightHandSide,
ScalarType eps,
bool verbose)
{
bool returnValue = true;
/* LabelSetImage members */
MITK_INFO(verbose) << "--- LabelSetImage Equal ---";
// number layers
returnValue = leftHandSide.GetNumberOfLayers() == rightHandSide.GetNumberOfLayers();
if (!returnValue)
{
MITK_INFO(verbose) << "Number of layers not equal.";
return false;
}
// total number labels
returnValue = leftHandSide.GetTotalNumberOfLabels() == rightHandSide.GetTotalNumberOfLabels();
if (!returnValue)
{
MITK_INFO(verbose) << "Total number of labels not equal.";
return false;
}
// active layer
returnValue = leftHandSide.GetActiveLayer() == rightHandSide.GetActiveLayer();
if (!returnValue)
{
MITK_INFO(verbose) << "Active layer not equal.";
return false;
}
if (4 == leftHandSide.GetDimension())
{
MITK_INFO(verbose) << "Can not compare image data for 4D images - skipping check.";
}
else
{
// working image data
returnValue = mitk::Equal((const mitk::Image &)leftHandSide, (const mitk::Image &)rightHandSide, eps, verbose);
if (!returnValue)
{
MITK_INFO(verbose) << "Working image data not equal.";
return false;
}
}
for (unsigned int layerIndex = 0; layerIndex < leftHandSide.GetNumberOfLayers(); layerIndex++)
{
if (4 == leftHandSide.GetDimension())
{
MITK_INFO(verbose) << "Can not compare image data for 4D images - skipping check.";
}
else
{
// layer image data
returnValue =
mitk::Equal(*leftHandSide.GetLayerImage(layerIndex), *rightHandSide.GetLayerImage(layerIndex), eps, verbose);
if (!returnValue)
{
MITK_INFO(verbose) << "Layer image data not equal.";
return false;
}
}
// layer labelset data
returnValue =
mitk::Equal(*leftHandSide.GetLabelSet(layerIndex), *rightHandSide.GetLabelSet(layerIndex), eps, verbose);
if (!returnValue)
{
MITK_INFO(verbose) << "Layer labelset data not equal.";
return false;
}
}
return returnValue;
}
/** Functor class that implements the label transfer and is used in conjunction with the itk::BinaryFunctorImageFilter.
* For details regarding the usage of the filter and the functor patterns, please see info of itk::BinaryFunctorImageFilter.
*/
template
class LabelTransferFunctor
{
public:
LabelTransferFunctor() {};
LabelTransferFunctor(const mitk::LabelSet* destinationLabelSet, mitk::Label::PixelType sourceBackground,
mitk::Label::PixelType destinationBackground, bool destinationBackgroundLocked,
mitk::Label::PixelType sourceLabel, mitk::Label::PixelType newDestinationLabel, mitk::MultiLabelSegmentation::MergeStyle mergeStyle,
mitk::MultiLabelSegmentation::OverwriteStyle overwriteStyle) :
m_DestinationLabelSet(destinationLabelSet), m_SourceBackground(sourceBackground),
m_DestinationBackground(destinationBackground), m_DestinationBackgroundLocked(destinationBackgroundLocked),
m_SourceLabel(sourceLabel), m_NewDestinationLabel(newDestinationLabel), m_MergeStyle(mergeStyle), m_OverwriteStyle(overwriteStyle)
{
};
~LabelTransferFunctor() {};
bool operator!=(const LabelTransferFunctor& other)const
{
return !(*this == other);
}
bool operator==(const LabelTransferFunctor& other) const
{
return this->m_SourceBackground == other.m_SourceBackground &&
this->m_DestinationBackground == other.m_DestinationBackground &&
this->m_DestinationBackgroundLocked == other.m_DestinationBackgroundLocked &&
this->m_SourceLabel == other.m_SourceLabel &&
this->m_NewDestinationLabel == other.m_NewDestinationLabel &&
this->m_MergeStyle == other.m_MergeStyle &&
this->m_OverwriteStyle == other.m_OverwriteStyle &&
this->m_DestinationLabelSet == other.m_DestinationLabelSet;
}
LabelTransferFunctor& operator=(const LabelTransferFunctor& other)
{
this->m_DestinationLabelSet = other.m_DestinationLabelSet;
this->m_SourceBackground = other.m_SourceBackground;
this->m_DestinationBackground = other.m_DestinationBackground;
this->m_DestinationBackgroundLocked = other.m_DestinationBackgroundLocked;
this->m_SourceLabel = other.m_SourceLabel;
this->m_NewDestinationLabel = other.m_NewDestinationLabel;
this->m_MergeStyle = other.m_MergeStyle;
this->m_OverwriteStyle = other.m_OverwriteStyle;
return *this;
}
inline TOutputpixel operator()(const TDestinationPixel& existingDestinationValue, const TSourcePixel& existingSourceValue)
{
if (existingSourceValue == this->m_SourceLabel)
{
if (mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks == this->m_OverwriteStyle)
{
return this->m_NewDestinationLabel;
}
else
{
if (existingDestinationValue == m_DestinationBackground)
{
if (!m_DestinationBackgroundLocked)
{
return this->m_NewDestinationLabel;
}
}
else
{
auto label = this->m_DestinationLabelSet->GetLabel(existingDestinationValue);
if (nullptr == label || !label->GetLocked())
{
return this->m_NewDestinationLabel;
}
}
}
}
else if (mitk::MultiLabelSegmentation::MergeStyle::Replace == this->m_MergeStyle
&& existingSourceValue == this->m_SourceBackground
&& existingDestinationValue == this->m_NewDestinationLabel
&& (mitk::MultiLabelSegmentation::OverwriteStyle::IgnoreLocks == this->m_OverwriteStyle
|| !this->m_DestinationBackgroundLocked))
{
return this->m_DestinationBackground;
}
return existingDestinationValue;
}
private:
const mitk::LabelSet* m_DestinationLabelSet = nullptr;
mitk::Label::PixelType m_SourceBackground = 0;
mitk::Label::PixelType m_DestinationBackground = 0;
bool m_DestinationBackgroundLocked = false;
mitk::Label::PixelType m_SourceLabel = 1;
mitk::Label::PixelType m_NewDestinationLabel = 1;
mitk::MultiLabelSegmentation::MergeStyle m_MergeStyle = mitk::MultiLabelSegmentation::MergeStyle::Replace;
mitk::MultiLabelSegmentation::OverwriteStyle m_OverwriteStyle = mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks;
};
/**Helper function used by TransferLabelContentAtTimeStep to allow the templating over different image dimensions in conjunction of AccessFixedPixelTypeByItk_n.*/
template
void TransferLabelContentAtTimeStepHelper(const itk::Image* itkSourceImage, mitk::Image* destinationImage,
const mitk::LabelSet* destinationLabelSet, mitk::Label::PixelType sourceBackground, mitk::Label::PixelType destinationBackground,
bool destinationBackgroundLocked, mitk::Label::PixelType sourceLabel, mitk::Label::PixelType newDestinationLabel, mitk::MultiLabelSegmentation::MergeStyle mergeStyle, mitk::MultiLabelSegmentation::OverwriteStyle overwriteStyle)
{
typedef itk::Image ContentImageType;
typename ContentImageType::Pointer itkDestinationImage;
mitk::CastToItkImage(destinationImage, itkDestinationImage);
auto sourceRegion = itkSourceImage->GetLargestPossibleRegion();
auto relevantRegion = itkDestinationImage->GetLargestPossibleRegion();
bool overlapping = relevantRegion.Crop(sourceRegion);
if (!overlapping)
{
mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; sourceImage and destinationImage seem to have no overlapping image region.";
}
typedef LabelTransferFunctor LabelTransferFunctorType;
typedef itk::BinaryFunctorImageFilter FilterType;
LabelTransferFunctorType transferFunctor(destinationLabelSet, sourceBackground, destinationBackground,
destinationBackgroundLocked, sourceLabel, newDestinationLabel, mergeStyle, overwriteStyle);
auto transferFilter = FilterType::New();
transferFilter->SetFunctor(transferFunctor);
transferFilter->InPlaceOn();
transferFilter->SetInput1(itkDestinationImage);
transferFilter->SetInput2(itkSourceImage);
transferFilter->GetOutput()->SetRequestedRegion(relevantRegion);
transferFilter->Update();
}
void mitk::TransferLabelContentAtTimeStep(
const Image* sourceImage, Image* destinationImage, const mitk::LabelSet* destinationLabelSet, const TimeStepType timeStep, mitk::Label::PixelType sourceBackground,
mitk::Label::PixelType destinationBackground, bool destinationBackgroundLocked, std::vector > labelMapping,
MultiLabelSegmentation::MergeStyle mergeStyle, MultiLabelSegmentation::OverwriteStyle overwriteStlye)
{
if (nullptr == sourceImage)
{
mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; sourceImage must not be null.";
}
if (nullptr == destinationImage)
{
mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; destinationImage must not be null.";
}
if (nullptr == destinationLabelSet)
{
mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; destinationLabelSet must not be null";
}
if (sourceImage == destinationImage && labelMapping.size() > 1)
{
MITK_DEBUG << "Warning. Using TransferLabelContentAtTimeStep or TransferLabelContent with equal source and destination and more then on label to transfer, can lead to wrong results. Please see documentation and verify that the usage is OK.";
}
Image::ConstPointer sourceImageAtTimeStep = SelectImageByTimeStep(sourceImage, timeStep);
Image::Pointer destinationImageAtTimeStep = SelectImageByTimeStep(destinationImage, timeStep);
if (nullptr == sourceImageAtTimeStep)
{
mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; sourceImage does not have the requested time step: " << timeStep;
}
if (nullptr == destinationImageAtTimeStep)
{
mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; destinationImage does not have the requested time step: " << timeStep;
}
for (const auto& [sourceLabel, newDestinationLabel] : labelMapping)
{
if (LabelSetImage::UnlabeledValue!=newDestinationLabel && nullptr == destinationLabelSet->GetLabel(newDestinationLabel))
{
mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep. Defined destination label does not exist in destinationImage. newDestinationLabel: " << newDestinationLabel;
}
AccessFixedPixelTypeByItk_n(sourceImageAtTimeStep, TransferLabelContentAtTimeStepHelper, (Label::PixelType), (destinationImageAtTimeStep, destinationLabelSet, sourceBackground, destinationBackground, destinationBackgroundLocked, sourceLabel, newDestinationLabel, mergeStyle, overwriteStlye));
destinationLabelSet->ModifyLabelEvent.Send(newDestinationLabel);
}
destinationImage->Modified();
}
void mitk::TransferLabelContent(
const Image* sourceImage, Image* destinationImage, const mitk::LabelSet* destinationLabelSet, mitk::Label::PixelType sourceBackground,
mitk::Label::PixelType destinationBackground, bool destinationBackgroundLocked, std::vector > labelMapping,
MultiLabelSegmentation::MergeStyle mergeStyle, MultiLabelSegmentation::OverwriteStyle overwriteStlye)
{
if (nullptr == sourceImage)
{
mitkThrow() << "Invalid call of TransferLabelContent; sourceImage must not be null.";
}
if (nullptr == destinationImage)
{
mitkThrow() << "Invalid call of TransferLabelContent; destinationImage must not be null.";
}
const auto sourceTimeStepCount = sourceImage->GetTimeGeometry()->CountTimeSteps();
if (sourceTimeStepCount != destinationImage->GetTimeGeometry()->CountTimeSteps())
{
mitkThrow() << "Invalid call of TransferLabelContent; mismatch between images in number of time steps.";
}
for (mitk::TimeStepType i = 0; i < sourceTimeStepCount; ++i)
{
TransferLabelContentAtTimeStep(sourceImage, destinationImage, destinationLabelSet, i, sourceBackground,
destinationBackground, destinationBackgroundLocked, labelMapping, mergeStyle, overwriteStlye);
}
}
void mitk::TransferLabelContentAtTimeStep(
const LabelSetImage* sourceImage, LabelSetImage* destinationImage, const TimeStepType timeStep,
std::vector > labelMapping,
MultiLabelSegmentation::MergeStyle mergeStyle, MultiLabelSegmentation::OverwriteStyle overwriteStlye)
{
if (nullptr == sourceImage)
{
mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep; sourceImage must not be null.";
}
const auto destinationLabelSet = destinationImage->GetLabelSet(destinationImage->GetActiveLayer());
for (const auto& mappingElement : labelMapping)
{
if (LabelSetImage::UnlabeledValue != mappingElement.first && !sourceImage->ExistLabel(mappingElement.first, sourceImage->GetActiveLayer()))
{
mitkThrow() << "Invalid call of TransferLabelContentAtTimeStep. Defined source label does not exist in sourceImage. SourceLabel: " << mappingElement.first;
}
}
TransferLabelContentAtTimeStep(sourceImage, destinationImage, destinationLabelSet, timeStep, LabelSetImage::UnlabeledValue, LabelSetImage::UnlabeledValue, destinationImage->GetUnlabeledLabelLock(),
labelMapping, mergeStyle, overwriteStlye);
}
void mitk::TransferLabelContent(
const LabelSetImage* sourceImage, LabelSetImage* destinationImage,
std::vector > labelMapping,
MultiLabelSegmentation::MergeStyle mergeStyle, MultiLabelSegmentation::OverwriteStyle overwriteStlye)
{
if (nullptr == sourceImage)
{
mitkThrow() << "Invalid call of TransferLabelContent; sourceImage must not be null.";
}
if (nullptr == destinationImage)
{
mitkThrow() << "Invalid call of TransferLabelContent; destinationImage must not be null.";
}
const auto sourceTimeStepCount = sourceImage->GetTimeGeometry()->CountTimeSteps();
if (sourceTimeStepCount != destinationImage->GetTimeGeometry()->CountTimeSteps())
{
mitkThrow() << "Invalid call of TransferLabelContent; images have no equal number of time steps.";
}
for (mitk::TimeStepType i = 0; i < sourceTimeStepCount; ++i)
{
TransferLabelContentAtTimeStep(sourceImage, destinationImage, i, labelMapping, mergeStyle, overwriteStlye);
}
}
diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp
index 0578c2e0d5..1f80c59170 100644
--- a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp
+++ b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp
@@ -1,134 +1,138 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "QmitkMultiWidgetLayoutSelectionWidget.h"
#include
#include
#include
#include
#include
QmitkMultiWidgetLayoutSelectionWidget::QmitkMultiWidgetLayoutSelectionWidget(QWidget* parent/* = 0*/)
: QWidget(parent)
{
Init();
}
void QmitkMultiWidgetLayoutSelectionWidget::Init()
{
ui.setupUi(this);
auto stylesheet = "QTableWidget::item{background-color: white;}\nQTableWidget::item:selected{background-color: #1C97EA;}";
ui.tableWidget->setStyleSheet(stylesheet);
connect(ui.tableWidget, &QTableWidget::itemSelectionChanged, this, &QmitkMultiWidgetLayoutSelectionWidget::OnTableItemSelectionChanged);
connect(ui.setLayoutPushButton, &QPushButton::clicked, this, &QmitkMultiWidgetLayoutSelectionWidget::OnSetLayoutButtonClicked);
connect(ui.loadLayoutPushButton, &QPushButton::clicked, this, &QmitkMultiWidgetLayoutSelectionWidget::OnLoadLayoutButtonClicked);
connect(ui.saveLayoutPushButton, &QPushButton::clicked, this, &QmitkMultiWidgetLayoutSelectionWidget::OnSaveLayoutButtonClicked);
connect(ui.selectDefaultLayoutComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &QmitkMultiWidgetLayoutSelectionWidget::OnLayoutPresetSelected);
ui.selectDefaultLayoutComboBox->addItem("Select a layout preset");
auto presetResources = us::GetModuleContext()->GetModule()->FindResources("/", "mxnLayout_*.json", false);
for (const auto& resource : presetResources)
{
us::ModuleResourceStream jsonStream(resource);
auto data = nlohmann::json::parse(jsonStream);
auto resourceName = data["name"].get();
ui.selectDefaultLayoutComboBox->addItem(QString::fromStdString(resourceName));
m_PresetMap[ui.selectDefaultLayoutComboBox->count() - 1] = data;
}
}
void QmitkMultiWidgetLayoutSelectionWidget::OnTableItemSelectionChanged()
{
QItemSelectionModel* selectionModel = ui.tableWidget->selectionModel();
int row = 0;
int column = 0;
QModelIndexList indices = selectionModel->selectedIndexes();
if (indices.size() > 0)
{
row = indices[0].row();
column = indices[0].column();
QModelIndex topLeft = ui.tableWidget->model()->index(0, 0, QModelIndex());
QModelIndex bottomRight = ui.tableWidget->model()->index(row, column, QModelIndex());
QItemSelection cellSelection;
cellSelection.select(topLeft, bottomRight);
selectionModel->select(cellSelection, QItemSelectionModel::Select);
}
}
void QmitkMultiWidgetLayoutSelectionWidget::OnSetLayoutButtonClicked()
{
int row = 0;
int column = 0;
QModelIndexList indices = ui.tableWidget->selectionModel()->selectedIndexes();
if (indices.size() > 0)
{
// find largest row and column
for (const auto& modelIndex : qAsConst(indices))
{
if (modelIndex.row() > row)
{
row = modelIndex.row();
}
if (modelIndex.column() > column)
{
column = modelIndex.column();
}
}
close();
emit LayoutSet(row+1, column+1);
}
ui.selectDefaultLayoutComboBox->setCurrentIndex(0);
}
void QmitkMultiWidgetLayoutSelectionWidget::OnSaveLayoutButtonClicked()
{
QString filename = QFileDialog::getSaveFileName(nullptr, "Select where to save the current layout", "", "MITK Window Layout (*.json)");
if (filename.isEmpty())
return;
+ QString fileExt(".json");
+ if (!filename.endsWith(fileExt))
+ filename += fileExt;
+
auto outStream = std::ofstream(filename.toStdString());
emit SaveLayout(&outStream);
}
void QmitkMultiWidgetLayoutSelectionWidget::OnLoadLayoutButtonClicked()
{
QString filename = QFileDialog::getOpenFileName(nullptr, "Load a layout file", "", "MITK Window Layouts (*.json)");
if (filename.isEmpty())
return;
ui.selectDefaultLayoutComboBox->setCurrentIndex(0);
std::ifstream f(filename.toStdString());
auto jsonData = nlohmann::json::parse(f);
emit LoadLayout(&jsonData);
}
void QmitkMultiWidgetLayoutSelectionWidget::OnLayoutPresetSelected(int index)
{
if (index == 0)
{
// First entry is only for description
return;
}
auto jsonData = m_PresetMap[index];
close();
emit LoadLayout(&jsonData);
}
diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp
index baad32e9c2..665c7a1714 100644
--- a/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp
+++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp
@@ -1,122 +1,125 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkBinaryThresholdBaseTool.h"
#include "mitkImageAccessByItk.h"
#include "mitkImageCast.h"
#include "mitkImageStatisticsHolder.h"
#include "mitkLabelSetImage.h"
#include
#include
mitk::BinaryThresholdBaseTool::BinaryThresholdBaseTool()
: m_SensibleMinimumThreshold(-100),
m_SensibleMaximumThreshold(+100),
m_LowerThreshold(1),
m_UpperThreshold(1)
{
}
mitk::BinaryThresholdBaseTool::~BinaryThresholdBaseTool()
{
}
void mitk::BinaryThresholdBaseTool::SetThresholdValues(double lower, double upper)
{
/* If value is not in the min/max range, do nothing. In that case, this
method will be called again with a proper value right after. The only
known case where this happens is with an [0.0, 1.0[ image, where value
could be an epsilon greater than the max. */
if (lower < m_SensibleMinimumThreshold
|| lower > m_SensibleMaximumThreshold
|| upper < m_SensibleMinimumThreshold
|| upper > m_SensibleMaximumThreshold)
{
return;
}
m_LowerThreshold = lower;
m_UpperThreshold = upper;
if (nullptr != this->GetPreviewSegmentation())
{
UpdatePreview();
}
}
void mitk::BinaryThresholdBaseTool::InitiateToolByInput()
{
const auto referenceImage = this->GetReferenceData();
if (nullptr != referenceImage)
{
m_SensibleMinimumThreshold = std::numeric_limits::max();
m_SensibleMaximumThreshold = std::numeric_limits::lowest();
Image::StatisticsHolderPointer statistics = referenceImage->GetStatistics();
for (unsigned int ts = 0; ts < referenceImage->GetTimeSteps(); ++ts)
{
m_SensibleMinimumThreshold = std::min(m_SensibleMinimumThreshold, static_cast(statistics->GetScalarValueMin()));
m_SensibleMaximumThreshold = std::max(m_SensibleMaximumThreshold, static_cast(statistics->GetScalarValueMax()));
}
if (m_LockedUpperThreshold)
{
m_LowerThreshold = (m_SensibleMaximumThreshold + m_SensibleMinimumThreshold) / 2.0;
m_UpperThreshold = m_SensibleMaximumThreshold;
}
else
{
double range = m_SensibleMaximumThreshold - m_SensibleMinimumThreshold;
m_LowerThreshold = m_SensibleMinimumThreshold + range / 3.0;
m_UpperThreshold = m_SensibleMinimumThreshold + 2 * range / 3.0;
}
bool isFloatImage = false;
if ((referenceImage->GetPixelType().GetPixelType() == itk::IOPixelEnum::SCALAR) &&
(referenceImage->GetPixelType().GetComponentType() == itk::IOComponentEnum::FLOAT ||
referenceImage->GetPixelType().GetComponentType() == itk::IOComponentEnum::DOUBLE))
{
isFloatImage = true;
}
IntervalBordersChanged.Send(m_SensibleMinimumThreshold, m_SensibleMaximumThreshold, isFloatImage);
ThresholdingValuesChanged.Send(m_LowerThreshold, m_UpperThreshold);
}
}
void mitk::BinaryThresholdBaseTool::DoUpdatePreview(const Image* inputAtTimeStep, const Image* /*oldSegAtTimeStep*/, LabelSetImage* previewImage, TimeStepType timeStep)
{
if (nullptr != inputAtTimeStep && nullptr != previewImage)
{
AccessByItk_n(inputAtTimeStep, ITKThresholding, (previewImage, timeStep));
}
}
template
void mitk::BinaryThresholdBaseTool::ITKThresholding(const itk::Image* inputImage,
- Image* segmentation,
+ LabelSetImage *segmentation,
unsigned int timeStep)
{
typedef itk::Image ImageType;
typedef itk::Image SegmentationType;
typedef itk::BinaryThresholdImageFilter ThresholdFilterType;
+ const auto activeValue = this->GetActiveLabelValueOfPreview();
+ this->SetSelectedLabels({activeValue});
+
typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New();
filter->SetInput(inputImage);
filter->SetLowerThreshold(m_LowerThreshold);
filter->SetUpperThreshold(m_UpperThreshold);
- filter->SetInsideValue(this->GetUserDefinedActiveLabel());
+ filter->SetInsideValue(activeValue);
filter->SetOutsideValue(0);
filter->Update();
segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep);
}
diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h
index cac6e3f6af..ff8940d165 100644
--- a/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h
+++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h
@@ -1,77 +1,78 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef mitkBinaryThresholdBaseTool_h
#define mitkBinaryThresholdBaseTool_h
#include
#include
#include
#include
#include
#include
namespace mitk
{
/**
\brief Base class for binary threshold tools.
\ingroup ToolManagerEtAl
\sa mitk::Tool
\sa QmitkInteractiveSegmentation
*/
class MITKSEGMENTATION_EXPORT BinaryThresholdBaseTool : public SegWithPreviewTool
{
public:
Message3 IntervalBordersChanged;
Message2 ThresholdingValuesChanged;
mitkClassMacro(BinaryThresholdBaseTool, SegWithPreviewTool);
virtual void SetThresholdValues(double lower, double upper);
protected:
BinaryThresholdBaseTool(); // purposely hidden
~BinaryThresholdBaseTool() override;
itkSetMacro(LockedUpperThreshold, bool);
itkGetMacro(LockedUpperThreshold, bool);
itkBooleanMacro(LockedUpperThreshold);
itkGetMacro(SensibleMinimumThreshold, ScalarType);
itkGetMacro(SensibleMaximumThreshold, ScalarType);
void InitiateToolByInput() override;
void DoUpdatePreview(const Image* inputAtTimeStep, const Image* oldSegAtTimeStep, LabelSetImage* previewImage, TimeStepType timeStep) override;
template
void ITKThresholding(const itk::Image* inputImage,
- Image* segmentation, unsigned int timeStep);
+ LabelSetImage *segmentation,
+ unsigned int timeStep);
private:
ScalarType m_SensibleMinimumThreshold;
ScalarType m_SensibleMaximumThreshold;
ScalarType m_LowerThreshold;
ScalarType m_UpperThreshold;
/** Indicates if the tool should behave like a single threshold tool (true)
or like a upper/lower threshold tool (false)*/
bool m_LockedUpperThreshold = false;
};
} // namespace
#endif
diff --git a/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp b/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp
index 84ab8d6774..688412dd2e 100644
--- a/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp
+++ b/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp
@@ -1,103 +1,114 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
// MITK
#include "mitkOtsuTool3D.h"
#include "mitkOtsuSegmentationFilter.h"
#include
#include
// us
#include
#include
#include
#include
namespace mitk
{
MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, OtsuTool3D, "Otsu Segmentation");
}
+mitk::OtsuTool3D::OtsuTool3D()
+ : SegWithPreviewTool()
+{
+ this->ResetsToEmptyPreviewOn();
+ this->UseSpecialPreviewColorOff();
+}
+
void mitk::OtsuTool3D::Activated()
{
Superclass::Activated();
m_NumberOfBins = 128;
m_NumberOfRegions = 2;
m_UseValley = false;
this->SetLabelTransferScope(LabelTransferScope::AllLabels);
this->SetLabelTransferMode(LabelTransferMode::AddLabel);
}
const char **mitk::OtsuTool3D::GetXPM() const
{
return nullptr;
}
us::ModuleResource mitk::OtsuTool3D::GetIconResource() const
{
us::Module *module = us::GetModuleContext()->GetModule();
us::ModuleResource resource = module->GetResource("Otsu.svg");
return resource;
}
const char* mitk::OtsuTool3D::GetName() const
{
return "Otsu";
}
void mitk::OtsuTool3D::DoUpdatePreview(const Image* inputAtTimeStep, const Image* /*oldSegAtTimeStep*/, LabelSetImage* previewImage, TimeStepType timeStep)
{
int numberOfThresholds = m_NumberOfRegions - 1;
mitk::OtsuSegmentationFilter::Pointer otsuFilter = mitk::OtsuSegmentationFilter::New();
otsuFilter->SetNumberOfThresholds(numberOfThresholds);
otsuFilter->SetValleyEmphasis(m_UseValley);
otsuFilter->SetNumberOfBins(m_NumberOfBins);
otsuFilter->SetInput(inputAtTimeStep);
otsuFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand);
try
{
otsuFilter->Update();
}
catch (...)
{
mitkThrow() << "itkOtsuFilter error (image dimension must be in {2, 3} and image must not be RGB)";
}
auto otsuResultImage = otsuFilter->GetOutput();
mitk::ImageReadAccessor newMitkImgAcc(otsuResultImage);
previewImage->SetVolume(newMitkImgAcc.GetData(), timeStep);
}
void mitk::OtsuTool3D::UpdatePrepare()
{
Superclass::UpdatePrepare();
auto preview = this->GetPreviewSegmentation();
auto labelset = preview->GetLabelSet(preview->GetActiveLayer());
- labelset->RemoveAllLabels();
+ for (LabelSetImage::GroupIndexType i = 0; iGetNumberOfLayers(); ++i)
+ {
+ preview->GetLabelSet(i)->RemoveAllLabels();
+ }
+
for (unsigned int i = 0; i < m_NumberOfRegions; ++i)
{
auto label = LabelSetImageHelper::CreateNewLabel(preview, "Otsu");
label->SetValue(i + 1);
labelset->AddLabel(label, false);
}
}
unsigned int mitk::OtsuTool3D::GetMaxNumberOfBins() const
{
const auto min = this->GetReferenceData()->GetStatistics()->GetScalarValueMin();
const auto max = this->GetReferenceData()->GetStatistics()->GetScalarValueMaxNoRecompute();
return static_cast(max - min) + 1;
}
diff --git a/Modules/Segmentation/Interactions/mitkOtsuTool3D.h b/Modules/Segmentation/Interactions/mitkOtsuTool3D.h
index 7185fed298..b93690340a 100644
--- a/Modules/Segmentation/Interactions/mitkOtsuTool3D.h
+++ b/Modules/Segmentation/Interactions/mitkOtsuTool3D.h
@@ -1,65 +1,65 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef mitkOtsuTool3D_h
#define mitkOtsuTool3D_h
#include "mitkSegWithPreviewTool.h"
#include
namespace us
{
class ModuleResource;
}
namespace mitk
{
class Image;
class MITKSEGMENTATION_EXPORT OtsuTool3D : public SegWithPreviewTool
{
public:
mitkClassMacro(OtsuTool3D, SegWithPreviewTool);
itkFactorylessNewMacro(Self);
itkCloneMacro(Self);
const char *GetName() const override;
const char **GetXPM() const override;
us::ModuleResource GetIconResource() const override;
void Activated() override;
itkSetMacro(NumberOfBins, unsigned int);
itkGetConstMacro(NumberOfBins, unsigned int);
itkSetMacro(NumberOfRegions, unsigned int);
itkGetConstMacro(NumberOfRegions, unsigned int);
itkSetMacro(UseValley, bool);
itkGetConstMacro(UseValley, bool);
itkBooleanMacro(UseValley);
/**Returns the number of max bins based on the current input image.*/
unsigned int GetMaxNumberOfBins() const;
protected:
- OtsuTool3D() = default;
+ OtsuTool3D();
~OtsuTool3D() = default;
void UpdatePrepare() override;
void DoUpdatePreview(const Image* inputAtTimeStep, const Image* oldSegAtTimeStep, LabelSetImage* previewImage, TimeStepType timeStep) override;
unsigned int m_NumberOfBins = 128;
unsigned int m_NumberOfRegions = 2;
bool m_UseValley = false;
}; // class
} // namespace
#endif
diff --git a/Modules/Segmentation/Interactions/mitkPickingTool.cpp b/Modules/Segmentation/Interactions/mitkPickingTool.cpp
index 96afc90601..6478b66ed6 100644
--- a/Modules/Segmentation/Interactions/mitkPickingTool.cpp
+++ b/Modules/Segmentation/Interactions/mitkPickingTool.cpp
@@ -1,256 +1,259 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkPickingTool.h"
#include "mitkProperties.h"
#include "mitkToolManager.h"
#include "mitkInteractionPositionEvent.h"
// us
#include
#include
#include
#include
#include "mitkITKImageImport.h"
#include "mitkImageAccessByItk.h"
#include "mitkImageCast.h"
#include "mitkImageTimeSelector.h"
#include
#include
#include
#include
namespace mitk
{
MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, PickingTool, "PickingTool");
}
mitk::PickingTool::PickingTool() : SegWithPreviewTool(false, "PressMoveReleaseAndPointSetting")
{
this->ResetsToEmptyPreviewOn();
}
mitk::PickingTool::~PickingTool()
{
}
const char **mitk::PickingTool::GetXPM() const
{
return nullptr;
}
const char *mitk::PickingTool::GetName() const
{
return "Picking";
}
us::ModuleResource mitk::PickingTool::GetIconResource() const
{
us::Module *module = us::GetModuleContext()->GetModule();
us::ModuleResource resource = module->GetResource("Picking.svg");
return resource;
}
void mitk::PickingTool::Activated()
{
Superclass::Activated();
m_PointSet = mitk::PointSet::New();
//ensure that the seed points are visible for all timepoints.
dynamic_cast(m_PointSet->GetTimeGeometry())->SetStepDuration(std::numeric_limits::max());
m_PointSetNode = mitk::DataNode::New();
m_PointSetNode->SetData(m_PointSet);
m_PointSetNode->SetName(std::string(this->GetName()) + "_PointSet");
m_PointSetNode->SetBoolProperty("helper object", true);
m_PointSetNode->SetColor(0.0, 1.0, 0.0);
m_PointSetNode->SetVisibility(true);
this->GetDataStorage()->Add(m_PointSetNode, this->GetToolManager()->GetWorkingData(0));
}
void mitk::PickingTool::Deactivated()
{
this->ClearSeeds();
// remove from data storage and disable interaction
GetDataStorage()->Remove(m_PointSetNode);
m_PointSetNode = nullptr;
m_PointSet = nullptr;
Superclass::Deactivated();
}
void mitk::PickingTool::ConnectActionsAndFunctions()
{
CONNECT_FUNCTION("ShiftSecondaryButtonPressed", OnAddPoint);
CONNECT_FUNCTION("ShiftPrimaryButtonPressed", OnAddPoint);
CONNECT_FUNCTION("DeletePoint", OnDelete);
}
void mitk::PickingTool::OnAddPoint(StateMachineAction*, InteractionEvent* interactionEvent)
{
if (!this->IsUpdating() && m_PointSet.IsNotNull())
{
const auto positionEvent = dynamic_cast(interactionEvent);
if (positionEvent != nullptr)
{
m_PointSet->InsertPoint(m_PointSet->GetSize(), positionEvent->GetPositionInWorld());
this->UpdatePreview();
}
}
}
void mitk::PickingTool::OnDelete(StateMachineAction*, InteractionEvent* /*interactionEvent*/)
{
if (!this->IsUpdating() && m_PointSet.IsNotNull())
{
// delete last seed point
if (this->m_PointSet->GetSize() > 0)
{
m_PointSet->RemovePointAtEnd(0);
this->UpdatePreview();
}
}
}
void mitk::PickingTool::ClearPicks()
{
this->ClearSeeds();
this->UpdatePreview();
}
bool mitk::PickingTool::HasPicks() const
{
return this->m_PointSet.IsNotNull() && this->m_PointSet->GetSize()>0;
}
void mitk::PickingTool::ClearSeeds()
{
if (this->m_PointSet.IsNotNull())
{
// renew pointset
this->m_PointSet = mitk::PointSet::New();
//ensure that the seed points are visible for all timepoints.
dynamic_cast(m_PointSet->GetTimeGeometry())->SetStepDuration(std::numeric_limits::max());
this->m_PointSetNode->SetData(this->m_PointSet);
}
}
template
void DoITKRegionGrowing(const itk::Image* oldSegImage,
mitk::Image* segmentation,
const mitk::PointSet* seedPoints,
unsigned int timeStep, const mitk::BaseGeometry* inputGeometry, const mitk::Label::PixelType outputValue,
const mitk::Label::PixelType backgroundValue,
bool& emptyTimeStep)
{
typedef itk::Image InputImageType;
typedef itk::Image OutputImageType;
typedef typename InputImageType::IndexType IndexType;
typedef itk::ConnectedThresholdImageFilter RegionGrowingFilterType;
using IndexMapType = std::map < mitk::Label::PixelType, std::vector >;
IndexMapType indexMap;
// convert world coordinates to image indices
for (auto pos = seedPoints->Begin(); pos != seedPoints->End(); ++pos)
{
IndexType seedIndex;
inputGeometry->WorldToIndex(pos->Value(), seedIndex);
const auto selectedLabel = oldSegImage->GetPixel(seedIndex);
if (selectedLabel != backgroundValue)
{
indexMap[selectedLabel].push_back(seedIndex);
}
}
typename OutputImageType::Pointer itkResultImage;
try
{
bool first = true;
typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New();
regionGrower->SetInput(oldSegImage);
regionGrower->SetReplaceValue(outputValue);
for (const auto& [label, indeces] : indexMap)
{
// perform region growing in desired segmented region
regionGrower->ClearSeeds();
for (const auto& index : indeces)
{
regionGrower->AddSeed(index);
}
regionGrower->SetLower(label);
regionGrower->SetUpper(label);
regionGrower->Update();
if (first)
{
itkResultImage = regionGrower->GetOutput();
}
else
{
typename itk::OrImageFilter::Pointer orFilter =
itk::OrImageFilter::New();
orFilter->SetInput1(regionGrower->GetOutput());
orFilter->SetInput2(itkResultImage);
orFilter->Update();
itkResultImage = orFilter->GetOutput();
}
first = false;
itkResultImage->DisconnectPipeline();
}
}
catch (const itk::ExceptionObject&)
{
return; // can't work
}
catch (...)
{
return;
}
if (itkResultImage.IsNotNull())
{
segmentation->SetVolume((void*)(itkResultImage->GetPixelContainer()->GetBufferPointer()),timeStep);
}
emptyTimeStep = itkResultImage.IsNull();
}
void mitk::PickingTool::DoUpdatePreview(const Image* /*inputAtTimeStep*/, const Image* oldSegAtTimeStep, LabelSetImage* previewImage, TimeStepType timeStep)
{
if (nullptr != oldSegAtTimeStep && nullptr != previewImage && m_PointSet.IsNotNull())
{
bool emptyTimeStep = true;
if (this->HasPicks())
{
- AccessFixedDimensionByItk_n(oldSegAtTimeStep, DoITKRegionGrowing, 3, (previewImage, this->m_PointSet, timeStep, oldSegAtTimeStep->GetGeometry(), this->GetUserDefinedActiveLabel(), mitk::LabelSetImage::UnlabeledValue, emptyTimeStep));
+ const auto activeValue = this->GetActiveLabelValueOfPreview();
+ this->SetSelectedLabels({activeValue});
+
+ AccessFixedDimensionByItk_n(oldSegAtTimeStep, DoITKRegionGrowing, 3, (previewImage, this->m_PointSet, timeStep, oldSegAtTimeStep->GetGeometry(), activeValue, mitk::LabelSetImage::UnlabeledValue, emptyTimeStep));
}
if (emptyTimeStep)
{
this->ResetPreviewContentAtTimeStep(timeStep);
}
}
}
diff --git a/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp b/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp
index 9b89cc0b21..ca649187e3 100644
--- a/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp
+++ b/Modules/Segmentation/Interactions/mitkSegWithPreviewTool.cpp
@@ -1,778 +1,818 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkSegWithPreviewTool.h"
#include "mitkToolManager.h"
#include "mitkColorProperty.h"
#include "mitkProperties.h"
#include "mitkDataStorage.h"
#include "mitkRenderingManager.h"
#include "mitkImageAccessByItk.h"
#include "mitkImageCast.h"
#include "mitkLabelSetImage.h"
#include "mitkMaskAndCutRoiImageFilter.h"
#include "mitkPadImageFilter.h"
#include "mitkNodePredicateGeometry.h"
#include "mitkSegTool2D.h"
mitk::SegWithPreviewTool::SegWithPreviewTool(bool lazyDynamicPreviews): Tool("dummy"), m_LazyDynamicPreviews(lazyDynamicPreviews)
{
m_ProgressCommand = ToolCommand::New();
}
mitk::SegWithPreviewTool::SegWithPreviewTool(bool lazyDynamicPreviews, const char* interactorType, const us::Module* interactorModule) : Tool(interactorType, interactorModule), m_LazyDynamicPreviews(lazyDynamicPreviews)
{
m_ProgressCommand = ToolCommand::New();
}
mitk::SegWithPreviewTool::~SegWithPreviewTool()
{
}
void mitk::SegWithPreviewTool::SetMergeStyle(MultiLabelSegmentation::MergeStyle mergeStyle)
{
m_MergeStyle = mergeStyle;
this->Modified();
}
void mitk::SegWithPreviewTool::SetOverwriteStyle(MultiLabelSegmentation::OverwriteStyle overwriteStyle)
{
m_OverwriteStyle = overwriteStyle;
this->Modified();
}
void mitk::SegWithPreviewTool::SetLabelTransferScope(LabelTransferScope labelTransferScope)
{
m_LabelTransferScope = labelTransferScope;
this->Modified();
}
void mitk::SegWithPreviewTool::SetLabelTransferMode(LabelTransferMode labelTransferMode)
{
m_LabelTransferMode = labelTransferMode;
this->Modified();
}
void mitk::SegWithPreviewTool::SetSelectedLabels(const SelectedLabelVectorType& labelsToTransfer)
{
m_SelectedLabels = labelsToTransfer;
this->Modified();
}
bool mitk::SegWithPreviewTool::CanHandle(const BaseData* referenceData, const BaseData* workingData) const
{
if (!Superclass::CanHandle(referenceData, workingData))
return false;
if (workingData == nullptr)
return false;
auto* referenceImage = dynamic_cast(referenceData);
if (referenceImage == nullptr)
return false;
auto* labelSet = dynamic_cast(workingData);
if (labelSet != nullptr)
return true;
auto* workingImage = dynamic_cast(workingData);
if (workingImage == nullptr)
return false;
// If the working image is a normal image and not a label set image
// it must have the same pixel type as a label set.
return MakeScalarPixelType< DefaultSegmentationDataType >() == workingImage->GetPixelType();
}
void mitk::SegWithPreviewTool::Activated()
{
Superclass::Activated();
this->GetToolManager()->RoiDataChanged +=
MessageDelegate(this, &SegWithPreviewTool::OnRoiDataChanged);
this->GetToolManager()->SelectedTimePointChanged +=
MessageDelegate(this, &SegWithPreviewTool::OnTimePointChanged);
m_ReferenceDataNode = this->GetToolManager()->GetReferenceData(0);
m_SegmentationInputNode = m_ReferenceDataNode;
m_LastTimePointOfUpdate = RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint();
if (m_PreviewSegmentationNode.IsNull())
{
m_PreviewSegmentationNode = DataNode::New();
m_PreviewSegmentationNode->SetProperty("color", ColorProperty::New(0.0, 1.0, 0.0));
m_PreviewSegmentationNode->SetProperty("name", StringProperty::New(std::string(this->GetName())+" preview"));
m_PreviewSegmentationNode->SetProperty("opacity", FloatProperty::New(0.3));
m_PreviewSegmentationNode->SetProperty("binary", BoolProperty::New(true));
m_PreviewSegmentationNode->SetProperty("helper object", BoolProperty::New(true));
}
if (m_SegmentationInputNode.IsNotNull())
{
this->ResetPreviewNode();
this->InitiateToolByInput();
}
else
{
this->GetToolManager()->ActivateTool(-1);
}
}
void mitk::SegWithPreviewTool::Deactivated()
{
this->GetToolManager()->RoiDataChanged -=
MessageDelegate(this, &SegWithPreviewTool::OnRoiDataChanged);
this->GetToolManager()->SelectedTimePointChanged -=
MessageDelegate(this, &SegWithPreviewTool::OnTimePointChanged);
m_SegmentationInputNode = nullptr;
m_ReferenceDataNode = nullptr;
m_WorkingPlaneGeometry = nullptr;
try
{
if (DataStorage *storage = this->GetToolManager()->GetDataStorage())
{
storage->Remove(m_PreviewSegmentationNode);
RenderingManager::GetInstance()->RequestUpdateAll();
}
}
catch (...)
{
// don't care
}
if (m_PreviewSegmentationNode.IsNotNull())
{
m_PreviewSegmentationNode->SetData(nullptr);
}
Superclass::Deactivated();
}
void mitk::SegWithPreviewTool::ConfirmSegmentation()
{
bool labelChanged = this->EnsureUpToDateUserDefinedActiveLabel();
if ((m_LazyDynamicPreviews && m_CreateAllTimeSteps) || labelChanged)
{ // The tool should create all time steps but is currently in lazy mode,
// thus ensure that a preview for all time steps is available.
this->UpdatePreview(true);
}
CreateResultSegmentationFromPreview();
RenderingManager::GetInstance()->RequestUpdateAll();
if (!m_KeepActiveAfterAccept)
{
this->GetToolManager()->ActivateTool(-1);
}
}
void mitk::SegWithPreviewTool::InitiateToolByInput()
{
//default implementation does nothing.
//implement in derived classes to change behavior
}
mitk::LabelSetImage* mitk::SegWithPreviewTool::GetPreviewSegmentation()
{
if (m_PreviewSegmentationNode.IsNull())
{
return nullptr;
}
return dynamic_cast(m_PreviewSegmentationNode->GetData());
}
const mitk::LabelSetImage* mitk::SegWithPreviewTool::GetPreviewSegmentation() const
{
if (m_PreviewSegmentationNode.IsNull())
{
return nullptr;
}
return dynamic_cast(m_PreviewSegmentationNode->GetData());
}
mitk::DataNode* mitk::SegWithPreviewTool::GetPreviewSegmentationNode()
{
return m_PreviewSegmentationNode;
}
const mitk::Image* mitk::SegWithPreviewTool::GetSegmentationInput() const
{
if (m_SegmentationInputNode.IsNull())
{
return nullptr;
}
return dynamic_cast(m_SegmentationInputNode->GetData());
}
const mitk::Image* mitk::SegWithPreviewTool::GetReferenceData() const
{
if (m_ReferenceDataNode.IsNull())
{
return nullptr;
}
return dynamic_cast(m_ReferenceDataNode->GetData());
}
template
void ClearBufferProcessing(ImageType* itkImage)
{
itkImage->FillBuffer(0);
}
void mitk::SegWithPreviewTool::ResetPreviewContentAtTimeStep(unsigned int timeStep)
{
auto previewImage = GetImageByTimeStep(this->GetPreviewSegmentation(), timeStep);
if (nullptr != previewImage)
{
AccessByItk(previewImage, ClearBufferProcessing);
}
}
void mitk::SegWithPreviewTool::ResetPreviewContent()
{
auto previewImage = this->GetPreviewSegmentation();
if (nullptr != previewImage)
{
auto castedPreviewImage =
dynamic_cast(previewImage);
if (nullptr == castedPreviewImage) mitkThrow() << "Application is on wrong state / invalid tool implementation. Preview image should always be of type LabelSetImage now.";
castedPreviewImage->ClearBuffer();
}
}
void mitk::SegWithPreviewTool::ResetPreviewNode()
{
if (m_IsUpdating)
{
mitkThrow() << "Used tool is implemented incorrectly. ResetPreviewNode is called while preview update is ongoing. Check implementation!";
}
itk::RGBPixel previewColor;
previewColor[0] = 0.0f;
previewColor[1] = 1.0f;
previewColor[2] = 0.0f;
const auto image = this->GetSegmentationInput();
if (nullptr != image)
{
LabelSetImage::ConstPointer workingImage =
dynamic_cast(this->GetToolManager()->GetWorkingData(0)->GetData());
if (workingImage.IsNotNull())
{
auto newPreviewImage = workingImage->Clone();
if (this->GetResetsToEmptyPreview())
{
newPreviewImage->ClearBuffer();
}
if (newPreviewImage.IsNull())
{
MITK_ERROR << "Cannot create preview helper objects. Unable to clone working image";
return;
}
m_PreviewSegmentationNode->SetData(newPreviewImage);
- auto* activeLayer = newPreviewImage->GetActiveLabelSet();
- auto* activeLabel = activeLayer->GetActiveLabel();
- if (m_UseSpecialPreviewColor)
+ auto* activeLabelSet = newPreviewImage->GetActiveLabelSet();
+ if (nullptr == activeLabelSet)
+ {
+ newPreviewImage->AddLayer();
+ activeLabelSet = newPreviewImage->GetActiveLabelSet();
+ }
+
+ auto* activeLabel = activeLabelSet->GetActiveLabel();
+ if (nullptr == activeLabel)
+ {
+ activeLabel = activeLabelSet->AddLabel("toolresult", previewColor);
+ activeLabelSet = newPreviewImage->GetActiveLabelSet();
+ activeLabelSet->UpdateLookupTable(activeLabel->GetValue());
+ }
+ else if (m_UseSpecialPreviewColor)
{
// Let's paint the feedback node green...
activeLabel->SetColor(previewColor);
- activeLayer->UpdateLookupTable(activeLabel->GetValue());
+ activeLabelSet->UpdateLookupTable(activeLabel->GetValue());
}
activeLabel->SetVisible(true);
}
else
{
Image::ConstPointer workingImageBin = dynamic_cast(this->GetToolManager()->GetWorkingData(0)->GetData());
if (workingImageBin.IsNotNull())
{
Image::Pointer newPreviewImage;
if (this->GetResetsToEmptyPreview())
{
newPreviewImage = Image::New();
newPreviewImage->Initialize(workingImageBin);
}
else
{
auto newPreviewImage = workingImageBin->Clone();
}
if (newPreviewImage.IsNull())
{
MITK_ERROR << "Cannot create preview helper objects. Unable to clone working image";
return;
}
m_PreviewSegmentationNode->SetData(newPreviewImage);
}
else
{
mitkThrow() << "Tool is an invalid state. Cannot setup preview node. Working data is an unsupported class and should have not been accepted by CanHandle().";
}
}
m_PreviewSegmentationNode->SetColor(previewColor);
m_PreviewSegmentationNode->SetOpacity(0.5);
int layer(50);
m_ReferenceDataNode->GetIntProperty("layer", layer);
m_PreviewSegmentationNode->SetIntProperty("layer", layer + 1);
if (DataStorage *ds = this->GetToolManager()->GetDataStorage())
{
if (!ds->Exists(m_PreviewSegmentationNode))
ds->Add(m_PreviewSegmentationNode, m_ReferenceDataNode);
}
}
}
mitk::SegWithPreviewTool::LabelMappingType mitk::SegWithPreviewTool::GetLabelMapping() const
{
LabelSetImage::LabelValueType offset = 0;
if (LabelTransferMode::AddLabel == m_LabelTransferMode && LabelTransferScope::ActiveLabel!=m_LabelTransferScope)
{
//If we are not just working on active label and transfer mode is add, we need to compute an offset for adding the
//preview labels instat of just mapping them to existing segmentation labels.
const auto segmentation = this->GetTargetSegmentation();
if (nullptr == segmentation)
mitkThrow() << "Invalid state of SegWithPreviewTool. Cannot GetLabelMapping if no target segmentation is set.";
auto labels = segmentation->GetLabels();
auto maxLabelIter = std::max_element(std::begin(labels), std::end(labels), [](const Label::Pointer& a, const Label::Pointer& b) {
return a->GetValue() < b->GetValue();
});
if (maxLabelIter != labels.end())
{
offset = maxLabelIter->GetPointer()->GetValue();
}
}
- LabelMappingType labelMapping = { { this->GetUserDefinedActiveLabel(),this->GetUserDefinedActiveLabel() } };
+ LabelMappingType labelMapping = {};
- if (LabelTransferScope::SelectedLabels == this->m_LabelTransferScope)
- {
- labelMapping.clear();
- for (auto label : this->m_SelectedLabels)
- {
- labelMapping.push_back({ label, label+offset });
- }
- }
- else if (LabelTransferScope::AllLabels == this->m_LabelTransferScope)
+ switch (this->m_LabelTransferScope)
{
- labelMapping.clear();
- const auto labelSet = this->GetPreviewSegmentation()->GetActiveLabelSet();
- for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelSet->IteratorConstEnd(); ++labelIter)
- {
- labelMapping.push_back({ labelIter->second->GetValue(),labelIter->second->GetValue()+offset });
- }
+ case LabelTransferScope::SelectedLabels:
+ {
+ for (auto label : this->m_SelectedLabels)
+ {
+ labelMapping.push_back({label, label + offset});
+ }
+ }
+ break;
+ case LabelTransferScope::AllLabels:
+ {
+ const auto labelSet = this->GetPreviewSegmentation()->GetActiveLabelSet();
+ for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelSet->IteratorConstEnd(); ++labelIter)
+ {
+ labelMapping.push_back({labelIter->second->GetValue(), labelIter->second->GetValue() + offset});
+ }
+ }
+ break;
+ default:
+ {
+ if (m_SelectedLabels.empty())
+ mitkThrow() << "Failed to generate label transfer mapping. Tool is in an invalid state, as "
+ "LabelTransferScope==ActiveLabel but no label is indicated as selected label. Check "
+ "implementation of derived tool class.";
+ if (m_SelectedLabels.size() > 1)
+ mitkThrow() << "Failed to generate label transfer mapping. Tool is in an invalid state, as "
+ "LabelTransferScope==ActiveLabel but more then one selected label is indicated."
+ "Should be only one. Check implementation of derived tool class.";
+ labelMapping.push_back({m_SelectedLabels.front(), this->GetUserDefinedActiveLabel()});
+ }
+ break;
}
return labelMapping;
}
void mitk::SegWithPreviewTool::TransferImageAtTimeStep(const Image* sourceImage, Image* destinationImage, const TimeStepType timeStep, const LabelMappingType& labelMapping)
{
try
{
Image::ConstPointer sourceImageAtTimeStep = this->GetImageByTimeStep(sourceImage, timeStep);
if (sourceImageAtTimeStep->GetPixelType() != destinationImage->GetPixelType())
{
mitkThrow() << "Cannot transfer images. Tool is in an invalid state, source image and destination image do not have the same pixel type. "
<< "Source pixel type: " << sourceImage->GetPixelType().GetTypeAsString()
<< "; destination pixel type: " << destinationImage->GetPixelType().GetTypeAsString();
}
if (!Equal(*(sourceImage->GetGeometry(timeStep)), *(destinationImage->GetGeometry(timeStep)), NODE_PREDICATE_GEOMETRY_DEFAULT_CHECK_COORDINATE_PRECISION, NODE_PREDICATE_GEOMETRY_DEFAULT_CHECK_DIRECTION_PRECISION, false))
{
mitkThrow() << "Cannot transfer images. Tool is in an invalid state, source image and destination image do not have the same geometry.";
}
if (nullptr != this->GetWorkingPlaneGeometry())
{
auto sourceSlice = SegTool2D::GetAffectedImageSliceAs2DImage(this->GetWorkingPlaneGeometry(), sourceImage, timeStep);
SegTool2D::WriteBackSegmentationResult(this->GetTargetSegmentationNode(), m_WorkingPlaneGeometry, sourceSlice, timeStep);
}
else
{ //take care of the full segmentation volume
auto sourceLSImage = dynamic_cast